AscEmu
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Player.cpp
Go to the documentation of this file.
1/*
2Copyright (c) 2014-2025 AscEmu Team <http://www.ascemu.org>
3This file is released under the MIT license. See README-MIT for more information.
4*/
5
6#include <zlib.h>
7
8#include "Player.hpp"
9
10#include "TradeData.hpp"
11#include "Chat/ChatDefines.hpp"
12#include "Data/WoWPlayer.hpp"
13#include "Chat/Channel.hpp"
14#include "Chat/ChannelMgr.hpp"
19#include "Management/Group.h"
25#include "Management/MailMgr.h"
27#include "Management/Skill.hpp"
31#include "Objects/GameObject.h"
33#include "Management/QuestMgr.h"
39#include "Objects/Container.hpp"
41#include "Server/Opcodes.hpp"
83#include "Server/World.h"
84#include "Server/WorldSocket.h"
94#include "Spell/Spell.hpp"
95#include "Spell/SpellAura.hpp"
97#include "Spell/SpellInfo.hpp"
98#include "Spell/SpellMgr.hpp"
102#include "Server/Definitions.h"
145#include "Storage/WorldStrings.h"
146#include "Utilities/Strings.hpp"
153#include "Server/EventMgr.h"
154#include "Server/WorldSession.h"
160#include <cstdarg>
161
162#include "Utilities/Narrow.hpp"
163
164#if VERSION_STRING > TBC
166#endif
167
168using namespace AscEmu::Packets;
169using namespace MapManagement::AreaManagement;
170using namespace InstanceDifficulty;
171
173
175{
176 guid = fields[0].asUint32();
177
178 std::string characterNameDB = fields[1].asCString();
179 AscEmu::Util::Strings::capitalize(characterNameDB);
180
181 name = characterNameDB;
182 race = fields[2].asUint8();
183 cl = fields[3].asUint8();
184 lastLevel = fields[4].asUint32();
185 gender = fields[5].asUint8();
186 lastZone = fields[6].asUint32();
187 lastOnline = fields[7].asUint32();
188 acct = fields[8].asUint32();
189 m_Group = nullptr;
190 subGroup = 0;
191 m_guild = 0;
194}
195
197{
198 if (m_Group != nullptr)
199 m_Group->RemovePlayer(this);
200}
201
203 m_updateMgr(this, static_cast<size_t>(worldConfig.server.compressionThreshold), 40000, 30000, 1000),
204 m_nextSave(Util::getMSTime() + worldConfig.getIntRate(INTRATE_SAVE)),
205 m_mailBox(std::make_unique<Mailbox>(guid)),
206 m_speedCheatDetector(std::make_unique<SpeedCheatDetector>()),
207 m_groupUpdateFlags(GROUP_UPDATE_FLAG_NONE),
208 m_TradeData(nullptr)
209{
210 //////////////////////////////////////////////////////////////////////////
214 //////////////////////////////////////////////////////////////////////////
215
216 //\todo Why is there a pointer to the same thing in a derived class? ToDo: sort this out..
218 memset(m_uint32Values, 0, (getSizeOfStructure(WoWPlayer)) * sizeof(uint32_t));
220
222 setGuidLow(guid);
223
224#if VERSION_STRING >= WotLK
225 setRuneRegen(0, 0.100000f);
226 setRuneRegen(1, 0.100000f);
227 setRuneRegen(2, 0.100000f);
228 setRuneRegen(3, 0.100000f);
229#endif
230
231 m_playerControler = this;
232
235
236 m_sentTeleportPosition.ChangeCoords({ 999999.0f, 999999.0f, 999999.0f });
237
238 // Zyres: initialise here because ItemInterface needs the guid from object data
239 m_itemInterface = std::make_unique<ItemInterface>(this);
240#if VERSION_STRING > TBC
241 // make_unique does not work with private ctor -Appled
242 m_achievementMgr = std::unique_ptr<AchievementMgr>(new AchievementMgr(this));
243#endif
244 m_taxi = std::make_unique<TaxiPath>();
245
248
249 std::fill(m_questlog.begin(), m_questlog.end(), nullptr);
250#if VERSION_STRING >= Cata
251 std::fill(_voidStorageItems.begin(), _voidStorageItems.end(), nullptr);
252#endif
253
254 // Override initialization from Unit class
256}
257
259{
261 {
262 sLogger.failure("Player deleted from non-logout player!");
263 sObjectMgr.removePlayer(this);
264 }
265
266 if (m_session)
267 {
268 m_session->SetPlayer(nullptr);
271 }
272
273 if (m_TradeData != nullptr)
274 cancelTrade(false);
275
276 if (Player* inviterPlayer = sObjectMgr.getPlayer(getGroupInviterId()))
277 inviterPlayer->setGroupInviterId(0);
278
279 if (m_duelPlayer != nullptr)
280 m_duelPlayer->m_duelPlayer = nullptr;
281
282 m_duelPlayer = nullptr;
283
284 m_cachedPets.clear();
286}
287
288//////////////////////////////////////////////////////////////////////////////////////////
289// Essential functions
290void Player::Update(unsigned long time_passed)
291{
292 if (getSession() && !getSession()->GetSocket())
293 {
294 getSession()->LogoutPlayer(false);
295 return;
296 }
297
298 if (!IsInWorld())
299 return;
300
301 Unit::Update(time_passed);
302 uint32_t mstime = Util::getMSTime();
303
304 if (m_attacking)
305 {
306 // Check attack timer.
307 if (isAttackReady(MELEE))
308 _eventAttack(false);
309
311 _eventAttack(true);
312 }
313
314 // Breathing
316 {
317 // keep subtracting timer
319 {
320 // not taking dmg yet
321 if (time_passed >= m_underwaterTime)
323 else
324 m_underwaterTime -= time_passed;
325 }
326
327 if (!m_underwaterTime)
328 {
329 // check last damage dealt timestamp, and if enough time has elapsed deal damage
330 if (mstime >= m_underwaterLastDamage)
331 {
332 uint32_t damage = getMaxHealth() / 10;
333
336 m_underwaterLastDamage = mstime + 1000;
337 }
338 }
339 }
340 else
341 {
342 // check if we're not on a full breath timer
344 {
345 // regenning
346 m_underwaterTime += (time_passed * 10);
347
349 {
352 }
353 }
354 }
355
356 // Lava Damage
358 {
359 // check last damage dealt timestamp, and if enough time has elapsed deal damage
360 if (mstime >= m_underwaterLastDamage)
361 {
362 uint32_t damage = getMaxHealth() / 5;
363
366 m_underwaterLastDamage = mstime + 1000;
367 }
368 }
369
370 // Autosave
371 if (mstime >= m_nextSave)
372 saveToDB(false);
373
374 // Exploration
375 if (mstime >= m_explorationTimer)
376 {
378 m_explorationTimer = mstime + 3000;
379 }
380
381 // Autocast Spells in Area
382 if (time_passed >= m_spellAreaUpdateTimer)
383 {
386 }
387 else
388 {
389 m_spellAreaUpdateTimer -= static_cast<uint16_t>(time_passed);
390 }
391
392 if (m_pvpTimer)
393 {
394 if (time_passed >= m_pvpTimer)
395 {
397 m_pvpTimer = 0;
398 }
399 else
400 m_pvpTimer -= time_passed;
401 }
402
403 indoorCheckUpdate(mstime);
404
406 {
407 m_drunkTimer += time_passed;
408
409 if (m_drunkTimer > 10000)
411 }
412
413 // Instance Hourly Limit
414 if (!m_instanceResetTimes.empty())
415 {
416 time_t now = Util::getTimeNow();
417 for (InstanceTimeMap::iterator itr = m_instanceResetTimes.begin(); itr != m_instanceResetTimes.end();)
418 {
419 if (itr->second < now)
420 m_instanceResetTimes.erase(itr++);
421 else
422 ++itr;
423 }
424 }
425
426 // Instance Binds
427 if (hasPendingBind())
428 {
429 if (m_pendingBindTimer <= time_passed)
430 {
431 // Player left the instance
432 if (m_pendingBindId == static_cast<uint32_t>(GetInstanceID()))
434 setPendingBind(0, 0);
435 }
436 else
437 {
438 m_pendingBindTimer -= time_passed;
439 }
440 }
441
442 if (m_timeSyncTimer > 0)
443 {
444 if (time_passed >= m_timeSyncTimer)
445 sendTimeSync();
446 else
447 m_timeSyncTimer -= time_passed;
448 }
449
450 if (time_passed >= m_partyUpdateTimer)
451 {
453 m_partyUpdateTimer = 1000;
454 }
455 else
456 {
457 m_partyUpdateTimer -= static_cast<uint16_t>(time_passed);
458 }
459
460 // Update items
461 if (m_itemUpdateTimer >= 1000)
462 {
466 }
467 else
468 {
469 m_itemUpdateTimer += time_passed;
470 }
471}
472
474{
475 if (auto transport = this->GetTransport())
476 {
477 this->SetPosition(transport->GetPositionX() + GetTransOffsetX(),
478 transport->GetPositionY() + GetTransOffsetY(),
479 transport->GetPositionZ() + GetTransOffsetZ(),
480 GetOrientation(), false);
481 }
482
483 // If we join an invalid instance and get booted out, this will prevent our stats from doubling :P
484 if (IsInWorld())
485 return;
486
487 m_beingPushed = true;
489
490 if (m_WorldMap == nullptr)
491 {
492 m_beingPushed = false;
494 return;
495 }
496
497 if (m_session)
499
500#if VERSION_STRING > TBC
502#endif
503}
504
506{
507 if (auto transport = this->GetTransport())
508 {
509 auto t_loc = transport->GetPosition();
510 this->SetPosition(t_loc.x + this->GetTransOffsetX(),
511 t_loc.y + this->GetTransOffsetY(),
512 t_loc.z + this->GetTransOffsetZ(),
513 this->GetOrientation(), false);
514 }
515
516 // If we join an invalid instance and get booted out, this will prevent our stats from doubling :P
517 if (IsInWorld())
518 return;
519
520 m_beingPushed = true;
521 Object::AddToWorld(pMapMgr);
522
523 if (m_WorldMap == nullptr)
524 {
525 m_beingPushed = false;
527 return;
528 }
529
530 if (m_session)
532
533#if VERSION_STRING > TBC
535#endif
536}
537
539{
541#if VERSION_STRING > TBC
542 m_achievementMgr->sendAllAchievementData(this);
543#endif
544
545 // Send initial power regen modifiers before push
550#if VERSION_STRING >= WotLK
552#endif
553}
554
556{
557 uint8_t class_ = getClass();
558 uint8_t startlevel = 1;
559
560 // Process create packet
562
563 if (m_teleportState == 2) // Worldport Ack
565
567 m_beingPushed = false;
569
570 // set fly if cheat is active
572
574
575 // Update PVP Situation
577
578 if (m_playerInfo->lastOnline + 900 < UNIXTIME) // did we logged out for more than 15 minutes?
580
582
583 sHookInterface.OnEnterWorld(this);
584
586 {
589 }
590
591 if (m_teleportState == 1 || m_enteringWorld) // First world enter
593
594 m_enteringWorld = false;
595 m_teleportState = 0;
596
597 // can only fly in outlands or northrend (northrend requires cold weather flying)
598 if (m_flyingAura && ((m_mapId != 530) && (m_mapId != 571 || !hasSpell(54197) && getDeathState() == ALIVE)))
599 {
601 m_flyingAura = 0;
602 }
603
604 // send weather
605 sWeatherMgr.sendWeather(this);
606
610
611 if (m_firstLogin)
612 {
613 if (class_ == DEATHKNIGHT)
614 startlevel = static_cast<uint8_t>(std::max(55, worldConfig.player.playerStartingLevel));
615 else
616 startlevel = static_cast<uint8_t>(worldConfig.player.playerStartingLevel);
617
618 applyLevelInfo(startlevel);
619
620 setHealthPct(100);
621
622 // Sometimes power types aren't initialized - so initialize it again
623 switch (getClass())
624 {
625 case WARRIOR:
628 break;
629 case ROGUE:
632 break;
633#if VERSION_STRING >= WotLK
634 case DEATHKNIGHT:
638 break;
639#endif
640#if VERSION_STRING >= Cata
641 case HUNTER:
644#endif
645 default:
647 break;
648 }
649 m_firstLogin = false;
650
652 castSpell(this, spellId, true);
653 }
654
657
659 {
660 if (m_WorldMap && reinterpret_cast<BattlegroundMap*>(m_WorldMap)->getBattleground() != nullptr && m_bg != reinterpret_cast<BattlegroundMap*>(m_WorldMap)->getBattleground())
661 reinterpret_cast<BattlegroundMap*>(m_WorldMap)->getBattleground()->portPlayer(this, true);
662 }
663
664 if (m_bg != nullptr)
665 {
666 m_bg->OnAddPlayer(this); // add buffs and so, must be after zone update and related aura removal
667 m_bg->onPlayerPushed(this);
668 }
669
670 m_changingMaps = false;
672
674 // Send enchant durations for unequipped items
676
678
679 if (m_resetTalents)
680 {
681 resetTalents();
682 m_resetTalents = false;
683 }
684
686
687#if VERSION_STRING == Mop
689
691 data.writeBits(0, 20);
692 data.flushBits();
693 sendPacket(&data);
694
696 data.writeBits(0, 19);
697 data.writeBit(1);
698 data.writeBits(0, 25);
699 data.flushBits();
700 data << uint16_t(0);
701 sendPacket(&data);
702
704 sendPacket(&data);
705
706#endif
707
710}
711
713{
716
719
720 if (m_bg)
721 m_bg->removePlayer(this, true);
722
723 // Cancel trade if it's active.
724 if (m_TradeData != nullptr)
725 cancelTrade(false);
726
727 //stop dueling
728 if (m_duelPlayer != nullptr)
730
731 //clear buyback
733
734 // Keep current pet active, Unit::RemoveFromWorld removes other summons
736
738 {
740 {
742 }
743 else
744 {
747
748 delete m_summonedObject;
749 }
750 m_summonedObject = nullptr;
751 }
752
753 if (IsInWorld())
754 {
757 }
758
759 m_changingMaps = true;
760 m_playerInfo->lastOnline = UNIXTIME; // don't destroy conjured items yet
761}
762
763//////////////////////////////////////////////////////////////////////////////////////////
764// Data
766void Player::setDuelArbiter(uint64_t guid) { write(playerData()->duel_arbiter, guid); }
767
770{
771 write(playerData()->player_flags, flags);
772
773#if VERSION_STRING == TBC
774 // TODO Fix this later
775 return;
776#endif
777
778 // Update player flags also to group
779 if (!IsInWorld() || getGroup() == nullptr)
780 return;
781
783}
786bool Player::hasPlayerFlags(uint32_t flags) const { return (getPlayerFlags() & flags) != 0; }
787
789{
790#if VERSION_STRING < Cata
791 return playerData()->guild_id;
792#else
793 return static_cast<uint32_t>(objectData()->data);
794#endif
795}
797{
798#if VERSION_STRING < Cata
799 write(playerData()->guild_id, guildId);
800#else
801 write(objectData()->data, WoWGuid(guildId, 0, HIGHGUID_TYPE_GUILD).getRawGuid());
802
803 if (guildId)
804 addPlayerFlags(PLAYER_FLAG_GUILD_LVL_ENABLED);
805 else
806 removePlayerFlags(PLAYER_FLAG_GUILD_LVL_ENABLED);
807
808 write(objectData()->field_type.parts.guild_id, static_cast<uint16_t>(guildId != 0 ? 1 : 0));
809#endif
810}
811
813void Player::setGuildRank(uint32_t guildRank) { write(playerData()->guild_rank, guildRank); }
814
815#if VERSION_STRING >= Cata
816uint32_t Player::getGuildLevel() const { return playerData()->guild_level; }
817void Player::setGuildLevel(uint32_t guildLevel) { write(playerData()->guild_level, guildLevel); }
818#endif
819
820//bytes begin
823
825void Player::setSkinColor(uint8_t color) { write(playerData()->player_bytes.s.skin_color, color); }
826
828void Player::setFace(uint8_t face) { write(playerData()->player_bytes.s.face, face); }
829
831void Player::setHairStyle(uint8_t style) { write(playerData()->player_bytes.s.hair_style, style); }
832
834void Player::setHairColor(uint8_t color) { write(playerData()->player_bytes.s.hair_color, color); }
835//bytes end
836
837//bytes2 begin
839void Player::setPlayerBytes2(uint32_t bytes2) { write(playerData()->player_bytes_2.raw, bytes2); }
840
842void Player::setFacialFeatures(uint8_t feature) { write(playerData()->player_bytes_2.s.facial_hair, feature); }
843
845void Player::setBankSlots(uint8_t slots) { write(playerData()->player_bytes_2.s.bank_slots, slots); }
846
848void Player::setRestState(uint8_t state) { write(playerData()->player_bytes_2.s.rest_state, state); }
849//bytes2 end
850
851//bytes3 begin
853void Player::setPlayerBytes3(uint32_t bytes3) { write(playerData()->player_bytes_3.raw, bytes3); }
854
856void Player::setPlayerGender(uint8_t gender) { write(playerData()->player_bytes_3.s.gender, gender); }
857
859void Player::setDrunkValue(uint8_t value) { write(playerData()->player_bytes_3.s.drunk_value, value); }
860
862void Player::setPvpRank(uint8_t rank) { write(playerData()->player_bytes_3.s.pvp_rank, rank); }
863
864#if VERSION_STRING >= TBC
865uint8_t Player::getArenaFaction() const { return playerData()->player_bytes_3.s.arena_faction; }
866void Player::setArenaFaction(uint8_t faction) { write(playerData()->player_bytes_3.s.arena_faction, faction); }
867#endif
868//bytes3 end
869
871void Player::setDuelTeam(uint32_t team) { write(playerData()->duel_team, team); }
872
874void Player::setGuildTimestamp(uint32_t timestamp) { write(playerData()->guild_timestamp, timestamp); }
875
876//QuestLog start
877uint32_t Player::getQuestLogEntryForSlot(uint8_t slot) const { return playerData()->quests[slot].quest_id; }
878void Player::setQuestLogEntryBySlot(uint8_t slot, uint32_t questEntry) { write(playerData()->quests[slot].quest_id, questEntry); }
879
880#if VERSION_STRING > Classic
881uint32_t Player::getQuestLogStateForSlot(uint8_t slot) const { return playerData()->quests[slot].state; }
882void Player::setQuestLogStateBySlot(uint8_t slot, uint32_t state) { write(playerData()->quests[slot].state, state); }
883#else
885{
886 //\todo: get last 1*8 bits as state
887 return playerData()->quests[slot].required_count_state;
888}
889
891{
892 //\todo: write last 1*8 bits as state
893 write(playerData()->quests[slot].required_count_state, state);
894}
895#endif
896
897#if VERSION_STRING > TBC
898uint64_t Player::getQuestLogRequiredMobOrGoForSlot(uint8_t slot) const { return playerData()->quests[slot].required_mob_or_go; }
899void Player::setQuestLogRequiredMobOrGoBySlot(uint8_t slot, uint64_t mobOrGoCount) { write(playerData()->quests[slot].required_mob_or_go, mobOrGoCount); }
900#elif VERSION_STRING == TBC
901uint32_t Player::getQuestLogRequiredMobOrGoForSlot(uint8_t slot) const { return playerData()->quests[slot].required_mob_or_go; }
902void Player::setQuestLogRequiredMobOrGoBySlot(uint8_t slot, uint32_t mobOrGoCount) { write(playerData()->quests[slot].required_mob_or_go, mobOrGoCount); }
903#else
905{
906 //\todo: get first 4*6 bits as required count
907 return playerData()->quests[slot].required_count_state;
908}
910{
911 //\todo: write first 4*6 bits as required count
912 write(playerData()->quests[slot].required_count_state, mobOrGoCount);
913}
914#endif
915
916uint32_t Player::getQuestLogExpireTimeForSlot(uint8_t slot) const { return playerData()->quests[slot].expire_time; }
917void Player::setQuestLogExpireTimeBySlot(uint8_t slot, uint32_t expireTime) { write(playerData()->quests[slot].expire_time, expireTime); }
918//QuestLog end
919
920//VisibleItem start
922void Player::setVisibleItemEntry(uint32_t slot, uint32_t entry) { write(playerData()->visible_items[slot].entry, entry); }
923
924#if VERSION_STRING > TBC
926{
927 if (pos > TEMP_ENCHANTMENT_SLOT)
928 return 0;
929
930 return playerData()->visible_items[slot].enchantment.raw[pos];
931}
933{
934 if (pos > TEMP_ENCHANTMENT_SLOT)
935 return;
936
937 write(playerData()->visible_items[slot].enchantment.raw[pos], enchantment);
938}
939#else
940uint32_t Player::getVisibleItemEnchantment(uint32_t slot, uint8_t pos) const { return playerData()->visible_items[slot].enchantment[pos]; }
941void Player::setVisibleItemEnchantment(uint32_t slot, uint8_t pos, uint32_t enchantment) { write(playerData()->visible_items[slot].enchantment[pos], enchantment); }
942#endif
943//VisibleItem end
944
946void Player::setInventorySlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->inventory_slot[slot], guid); }
947
949void Player::setPackSlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->pack_slot[slot], guid); }
950
952void Player::setBankSlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->bank_slot[slot], guid); }
953
955void Player::setBankBagSlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->bank_bag_slot[slot], guid); }
956
958void Player::setVendorBuybackSlot(uint8_t slot, uint64_t guid) { write(playerData()->vendor_buy_back_slot[slot], guid); }
959
960#if VERSION_STRING < Cata
961uint64_t Player::getKeyRingSlotItemGuid(uint8_t slot) const { return playerData()->key_ring_slot[slot]; }
962void Player::setKeyRingSlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->key_ring_slot[slot], guid); }
963#endif
964
965#if VERSION_STRING == TBC
966uint64_t Player::getVanityPetSlotItemGuid(uint8_t slot) const { return playerData()->vanity_pet_slot[slot]; }
967void Player::setVanityPetSlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->vanity_pet_slot[slot], guid); }
968#endif
969
970#if VERSION_STRING == WotLK
971uint64_t Player::getCurrencyTokenSlotItemGuid(uint8_t slot) const { return playerData()->currencytoken_slot[slot]; }
972void Player::setCurrencyTokenSlotItemGuid(uint8_t slot, uint64_t guid) { write(playerData()->currencytoken_slot[slot], guid); }
973#endif
974
976void Player::setFarsightGuid(uint64_t farsightGuid) { write(playerData()->farsight_guid, farsightGuid); }
977
978#if VERSION_STRING > Classic
979uint64_t Player::getKnownTitles(uint8_t index) const { return playerData()->field_known_titles[index]; }
980void Player::setKnownTitles(uint8_t index, uint64_t title) { write(playerData()->field_known_titles[index], title); }
981#endif
982
983#if VERSION_STRING > Classic
984uint32_t Player::getChosenTitle() const { return playerData()->chosen_title; }
985void Player::setChosenTitle(uint32_t title) { write(playerData()->chosen_title, title); }
986#endif
987
988#if VERSION_STRING == WotLK
989uint64_t Player::getKnownCurrencies() const { return playerData()->field_known_currencies; }
990void Player::setKnownCurrencies(uint64_t currencies) { write(playerData()->field_known_currencies, currencies); }
991#endif
992
993uint32_t Player::getXp() const { return playerData()->xp; }
994void Player::setXp(uint32_t xp) { write(playerData()->xp, xp); }
995void Player::addXP(uint32_t xp) { write(playerData()->xp, getXp() + xp); }
996
998void Player::setNextLevelXp(uint32_t xp) { write(playerData()->next_level_xp, xp); }
999
1000#if VERSION_STRING < Cata
1001uint16_t Player::getSkillInfoId(uint32_t index) const { return playerData()->skill_info[index].id; }
1002uint16_t Player::getSkillInfoStep(uint32_t index) const { return playerData()->skill_info[index].step; }
1003uint16_t Player::getSkillInfoCurrentValue(uint32_t index) const { return playerData()->skill_info[index].current_value; }
1004uint16_t Player::getSkillInfoMaxValue(uint32_t index) const { return playerData()->skill_info[index].max_value; }
1005uint16_t Player::getSkillInfoBonusTemporary(uint32_t index) const { return playerData()->skill_info[index].bonus_temporary; }
1006uint16_t Player::getSkillInfoBonusPermanent(uint32_t index) const { return playerData()->skill_info[index].bonus_permanent; }
1007void Player::setSkillInfoId(uint32_t index, uint16_t id) { write(playerData()->skill_info[index].id, id); }
1008void Player::setSkillInfoStep(uint32_t index, uint16_t step) { write(playerData()->skill_info[index].step, step); }
1009void Player::setSkillInfoCurrentValue(uint32_t index, uint16_t current) { write(playerData()->skill_info[index].current_value, current); }
1010void Player::setSkillInfoMaxValue(uint32_t index, uint16_t max) { write(playerData()->skill_info[index].max_value, max); }
1011void Player::setSkillInfoBonusTemporary(uint32_t index, uint16_t bonus) { write(playerData()->skill_info[index].bonus_temporary, bonus); }
1012void Player::setSkillInfoBonusPermanent(uint32_t index, uint16_t bonus) { write(playerData()->skill_info[index].bonus_permanent, bonus); }
1013#else
1014uint16_t Player::getSkillInfoId(uint32_t index, uint8_t offset) const { return *(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_line[index]) + offset); }
1015uint16_t Player::getSkillInfoStep(uint32_t index, uint8_t offset) const { return *(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_step[index]) + offset); }
1016uint16_t Player::getSkillInfoCurrentValue(uint32_t index, uint8_t offset) const { return *(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_rank[index]) + offset); }
1017uint16_t Player::getSkillInfoMaxValue(uint32_t index, uint8_t offset) const { return *(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_max_rank[index]) + offset); }
1018uint16_t Player::getSkillInfoBonusTemporary(uint32_t index, uint8_t offset) const { return *(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_mod[index]) + offset); }
1019uint16_t Player::getSkillInfoBonusPermanent(uint32_t index, uint8_t offset) const { return *(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_talent[index]) + offset); }
1020uint32_t Player::getProfessionSkillLine(uint32_t index) const { return playerData()->profession_skill_line[index]; }
1021void Player::setSkillInfoId(uint32_t index, uint8_t offset, uint16_t id) { write(*(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_line[index]) + offset), id); }
1022void Player::setSkillInfoStep(uint32_t index, uint8_t offset, uint16_t step) { write(*(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_step[index]) + offset), step); }
1023void Player::setSkillInfoCurrentValue(uint32_t index, uint8_t offset, uint16_t current) { write(*(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_rank[index]) + offset), current); }
1024void Player::setSkillInfoMaxValue(uint32_t index, uint8_t offset, uint16_t max) { write(*(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_max_rank[index]) + offset), max); }
1025void Player::setSkillInfoBonusTemporary(uint32_t index, uint8_t offset, uint16_t bonus) { write(*(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_mod[index]) + offset), bonus); }
1026void Player::setSkillInfoBonusPermanent(uint32_t index, uint8_t offset, uint16_t bonus) { write(*(((uint16_t*)&playerData()->field_skill_info.skill_info_parts.skill_talent[index]) + offset), bonus); }
1027void Player::setProfessionSkillLine(uint32_t index, uint32_t value) { write(playerData()->profession_skill_line[index], value); }
1028#endif
1029
1031{
1032#if VERSION_STRING < Cata
1034#else
1035 return m_specs[m_talentActiveSpec].getTalentPoints();
1036#endif
1037}
1038
1039#if VERSION_STRING < Cata
1040void Player::setFreeTalentPoints(uint32_t points) { write(playerData()->character_points_1, points); }
1041#endif
1042
1044{
1045#if VERSION_STRING < Cata
1047#else
1049#endif
1050}
1051
1053{
1054 if (points > worldConfig.player.maxProfessions)
1055 points = worldConfig.player.maxProfessions;
1056
1057#if VERSION_STRING < Cata
1058 write(playerData()->character_points_2, points);
1059#else
1060 write(playerData()->character_points_1, points);
1061#endif
1062}
1063
1065{
1067 value += amount;
1068
1069 if (value < 0)
1070 value = 0;
1071
1073}
1074
1076void Player::setTrackCreature(uint32_t id) { write(playerData()->track_creatures, id); }
1077
1079void Player::setTrackResource(uint32_t id) { write(playerData()->track_resources, id); }
1080
1083
1086
1089
1090#if VERSION_STRING >= TBC
1091uint32_t Player::getExpertise() const { return playerData()->expertise; }
1094
1095uint32_t Player::getOffHandExpertise() const { return playerData()->offhand_expertise; }
1098#endif
1099
1102
1104void Player::setRangedCritPercentage(float value) { write(playerData()->ranged_crit_pct, value); }
1105
1106#if VERSION_STRING >= TBC
1107float Player::getOffHandCritPercentage() const { return playerData()->offhand_crit_pct; }
1108void Player::setOffHandCritPercentage(float value) { write(playerData()->offhand_crit_pct, value); }
1109
1110float Player::getSpellCritPercentage(uint8_t school) const { return playerData()->spell_crit_pct[school]; }
1111void Player::setSpellCritPercentage(uint8_t school, float value) { write(playerData()->spell_crit_pct[school], value); }
1112
1113uint32_t Player::getShieldBlock() const { return playerData()->shield_block; }
1115#endif
1116
1117#if VERSION_STRING >= WotLK
1118float Player::getShieldBlockCritPercentage() const { return playerData()->shield_block_crit_pct; }
1119void Player::setShieldBlockCritPercentage(float value) { write(playerData()->shield_block_crit_pct, value); }
1120#endif
1121
1123{
1125 return playerData()->explored_zones[idx];
1126 return 0;
1127}
1128
1130{
1132 write(playerData()->explored_zones[idx], data);
1133}
1134
1136void Player::setSelfResurrectSpell(uint32_t spell) { write(playerData()->self_resurrection_spell, spell); }
1137
1139void Player::setWatchedFaction(uint32_t factionId) { write(playerData()->field_watched_faction_idx, factionId); }
1140
1141#if VERSION_STRING == TBC
1142float Player::getManaRegeneration() const { return playerData()->field_mod_mana_regen; }
1143void Player::setManaRegeneration(float value) { write(playerData()->field_mod_mana_regen, value); }
1144
1145float Player::getManaRegenerationWhileCasting() const { return playerData()->field_mod_mana_regen_interrupt; }
1146void Player::setManaRegenerationWhileCasting(float value) { write(playerData()->field_mod_mana_regen_interrupt, value); }
1147#endif
1148
1150{
1151#if VERSION_STRING > Classic
1152 return playerData()->field_max_level;
1153#else
1154 return m_classicMaxLevel;
1155#endif
1156}
1157
1159{
1160#if VERSION_STRING > Classic
1161 write(playerData()->field_max_level, level);
1162#else
1163 m_classicMaxLevel = level;
1164#endif
1165}
1166
1167#if VERSION_STRING >= WotLK
1168float Player::getRuneRegen(uint8_t rune) const { return playerData()->rune_regen[rune]; }
1169void Player::setRuneRegen(uint8_t rune, float regen) { write(playerData()->rune_regen[rune], regen); }
1170#endif
1171
1173void Player::setRestStateXp(uint32_t xp) { write(playerData()->rest_state_xp, xp); }
1174
1175#if VERSION_STRING < Cata
1177void Player::setCoinage(uint32_t coinage) { write(playerData()->field_coinage, coinage); }
1178bool Player::hasEnoughCoinage(uint32_t coinage) const { return getCoinage() >= coinage; }
1179void Player::modCoinage(int32_t coinage)
1180{
1181 setCoinage(getCoinage() + coinage);
1182}
1183#else
1185void Player::setCoinage(uint64_t coinage) { write(playerData()->field_coinage, coinage); }
1186bool Player::hasEnoughCoinage(uint64_t coinage) const { return getCoinage() >= coinage; }
1188{
1189 setCoinage(getCoinage() + coinage);
1190}
1191#endif
1192
1193#if VERSION_STRING == Classic
1195void Player::setResistanceBuffModPositive(uint8_t type, uint32_t value) { write(playerData()->resistance_buff_mod_positive[type], value); }
1196
1198void Player::setResistanceBuffModNegative(uint8_t type, uint32_t value) { write(playerData()->resistance_buff_mod_negative[type], value); }
1199#endif
1200
1202void Player::setModDamageDonePositive(uint16_t school, uint32_t value) { write(playerData()->field_mod_damage_done_positive[school], value); }
1204
1206void Player::setModDamageDoneNegative(uint16_t school, uint32_t value) { write(playerData()->field_mod_damage_done_negative[school], value); }
1208
1210void Player::setModDamageDonePct(float damagePct, uint8_t shool) { write(playerData()->field_mod_damage_done_pct[shool], damagePct); }
1211
1212#if VERSION_STRING >= TBC
1213uint32_t Player::getModHealingDone() const { return playerData()->field_mod_healing_done; }
1214void Player::setModHealingDone(uint32_t value) { write(playerData()->field_mod_healing_done, value); }
1216
1217uint32_t Player::getModTargetResistance() const { return playerData()->field_mod_target_resistance; }
1218void Player::setModTargetResistance(uint32_t value) { write(playerData()->field_mod_target_resistance, value); }
1220
1221uint32_t Player::getModTargetPhysicalResistance() const { return playerData()->field_mod_target_physical_resistance; }
1222void Player::setModTargetPhysicalResistance(uint32_t value) { write(playerData()->field_mod_target_physical_resistance, value); }
1224#endif
1225
1227void Player::setPlayerFieldBytes(uint32_t bytes) { write(playerData()->player_field_bytes.raw, bytes); }
1228
1230void Player::setPlayerFieldBytesMiscFlag(uint8_t miscFlag) { write(playerData()->player_field_bytes.s.misc_flags, miscFlag); }
1233
1235void Player::setEnabledActionBars(uint8_t actionBarId) { write(playerData()->player_field_bytes.s.enabled_action_bars, actionBarId); }
1236
1237#if VERSION_STRING < Cata
1238uint32_t Player::getAmmoId() const { return playerData()->ammo_id; }
1239void Player::setAmmoId(uint32_t id) { write(playerData()->ammo_id, id); }
1240#endif
1241
1243void Player::setBuybackPriceSlot(uint8_t slot, uint32_t price) { write(playerData()->field_buy_back_price[slot], price); }
1244
1246void Player::setBuybackTimestampSlot(uint8_t slot, uint32_t timestamp) { write(playerData()->field_buy_back_timestamp[slot], timestamp); }
1247
1248#if VERSION_STRING > Classic
1249uint32_t Player::getFieldKills() const { return playerData()->field_kills.raw; }
1250void Player::setFieldKills(uint32_t kills) { write(playerData()->field_kills.raw, kills); }
1251#endif
1252
1253#if VERSION_STRING > Classic
1254#if VERSION_STRING < Cata
1255 uint32_t Player::getContributionToday() const { return playerData()->field_contribution_today; }
1256 void Player::setContributionToday(uint32_t contribution) { write(playerData()->field_contribution_today, contribution); }
1257
1258 uint32_t Player::getContributionYesterday() const { return playerData()->field_contribution_yesterday; }
1259 void Player::setContributionYesterday(uint32_t contribution) { write(playerData()->field_contribution_yesterday, contribution); }
1260#endif
1261#endif
1262
1264void Player::setLifetimeHonorableKills(uint32_t kills) { write(playerData()->field_lifetime_honorable_kills, kills); }
1265
1266#if VERSION_STRING != Mop
1268void Player::setPlayerFieldBytes2(uint32_t bytes) { write(playerData()->player_field_bytes_2.raw, bytes); }
1269
1271void Player::setAuraVision(uint8_t auraVision) { write(playerData()->player_field_bytes_2.s.aura_vision, auraVision); }
1272void Player::addAuraVision(uint8_t auraVision) { setAuraVision(getAuraVision() | auraVision); }
1273void Player::removeAuraVision(uint8_t auraVision) { setAuraVision(getAuraVision() & ~auraVision); }
1274#endif
1275
1276uint32_t Player::getCombatRating(uint8_t combatRating) const { return playerData()->field_combat_rating[combatRating]; }
1277void Player::setCombatRating(uint8_t combatRating, uint32_t value) { write(playerData()->field_combat_rating[combatRating], value); }
1278void Player::modCombatRating(uint8_t combatRating, int32_t value) { setCombatRating(combatRating, getCombatRating(combatRating) + value); }
1279
1280#if VERSION_STRING > Classic
1281 // field_arena_team_info start
1282uint32_t Player::getArenaTeamId(uint8_t teamSlot) const { return playerData()->field_arena_team_info[teamSlot].team_id; }
1283void Player::setArenaTeamId(uint8_t teamSlot, uint32_t teamId) { write(playerData()->field_arena_team_info[teamSlot].team_id, teamId); }
1284
1285uint32_t Player::getArenaTeamMemberRank(uint8_t teamSlot) const { return playerData()->field_arena_team_info[teamSlot].member_rank; }
1286void Player::setArenaTeamMemberRank(uint8_t teamSlot, uint32_t rank) { write(playerData()->field_arena_team_info[teamSlot].member_rank, rank); }
1287 // field_arena_team_info end
1288#endif
1289
1290#if VERSION_STRING > Classic
1291#if VERSION_STRING < Cata
1292uint32_t Player::getHonorCurrency() const { return playerData()->field_honor_currency; }
1293void Player::setHonorCurrency(uint32_t amount) { write(playerData()->field_honor_currency, amount); }
1294void Player::modHonorCurrency(int32_t value) { setArenaCurrency(getArenaCurrency() + value); }
1295
1296uint32_t Player::getArenaCurrency() const { return playerData()->field_arena_currency; }
1297void Player::setArenaCurrency(uint32_t amount) { write(playerData()->field_arena_currency, amount); }
1298void Player::modArenaCurrency(int32_t value) { setArenaCurrency(getArenaCurrency() + value); }
1299#endif
1300#endif
1301
1302#if VERSION_STRING >= WotLK
1303uint32_t Player::getNoReagentCost(uint8_t index) const { return playerData()->no_reagent_cost[index]; }
1304void Player::setNoReagentCost(uint8_t index, uint32_t value) { write(playerData()->no_reagent_cost[index], value); }
1305
1306uint32_t Player::getGlyphSlot(uint16_t slot) const { return playerData()->field_glyph_slots[slot]; }
1307void Player::setGlyphSlot(uint16_t slot, uint32_t glyph) { write(playerData()->field_glyph_slots[slot], glyph); }
1308
1309uint32_t Player::getGlyph(uint16_t slot) const { return playerData()->field_glyphs[slot]; }
1310void Player::setGlyph(uint16_t slot, uint32_t glyph) { write(playerData()->field_glyphs[slot], glyph); }
1311
1312uint32_t Player::getGlyphsEnabled() const { return playerData()->glyphs_enabled; }
1313void Player::setGlyphsEnabled(uint32_t glyphs) { write(playerData()->glyphs_enabled, glyphs); }
1314#endif
1315
1316
1317//////////////////////////////////////////////////////////////////////////////////////////
1318// Movement
1319
1320#if VERSION_STRING >= Cata
1321void Player::sendForceMovePacket(UnitSpeedType speed_type, float speed)
1322{
1323 WorldPacket data(60);
1324 switch (speed_type)
1325 {
1326 case TYPE_WALK:
1327 {
1330 break;
1331 }
1332 case TYPE_RUN:
1333 {
1336 break;
1337 }
1338 case TYPE_RUN_BACK:
1339 {
1342 break;
1343 }
1344 case TYPE_SWIM:
1345 {
1348 break;
1349 }
1350 case TYPE_SWIM_BACK:
1351 {
1354 break;
1355 }
1356 case TYPE_TURN_RATE:
1357 {
1359 //movement_info.Write(data, SMSG_FORCE_TURN_RATE_CHANGE, speed);
1360 break;
1361 }
1362 case TYPE_FLY:
1363 {
1366 break;
1367 }
1368 case TYPE_FLY_BACK:
1369 {
1371 //movement_info.Write(data, SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, speed);
1372 break;
1373 }
1374 case TYPE_PITCH_RATE:
1375 {
1377 //movement_info.Write(data, SMSG_FORCE_PITCH_RATE_CHANGE, speed);
1378 break;
1379 }
1380 }
1381
1382 sendMessageToSet(&data, true);
1383}
1384
1386{
1387 WorldPacket data;
1388 ObjectGuid guid = getGuid();
1389
1390 switch (speed_type)
1391 {
1392 case TYPE_WALK:
1393 {
1394 data.Initialize(MSG_MOVE_SET_WALK_SPEED, 1 + 8 + 4 + 4);
1396 break;
1397 }
1398 case TYPE_RUN:
1399 {
1400 data.Initialize(MSG_MOVE_SET_RUN_SPEED, 1 + 8 + 4 + 4);
1401#if VERSION_STRING == Mop
1402 data.writeBit(guid[1]);
1403 data.writeBit(guid[7]);
1404 data.writeBit(guid[4]);
1405 data.writeBit(guid[2]);
1406 data.writeBit(guid[5]);
1407 data.writeBit(guid[3]);
1408 data.writeBit(guid[6]);
1409 data.writeBit(guid[0]);
1410
1411 data.WriteByteSeq(guid[1]);
1412
1413 data << uint32_t(0);
1414
1415 data.WriteByteSeq(guid[7]);
1416 data.WriteByteSeq(guid[3]);
1417 data.WriteByteSeq(guid[0]);
1418
1419 data << float(speed);
1420
1421 data.WriteByteSeq(guid[2]);
1422 data.WriteByteSeq(guid[4]);
1423 data.WriteByteSeq(guid[6]);
1424 data.WriteByteSeq(guid[5]);
1425#else
1427#endif
1428 break;
1429 }
1430 case TYPE_RUN_BACK:
1431 {
1432 data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 1 + 8 + 4 + 4);
1434 break;
1435 }
1436 case TYPE_SWIM:
1437 {
1438 data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 1 + 8 + 4 + 4);
1440 break;
1441 }
1442 case TYPE_SWIM_BACK:
1443 {
1444 data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 1 + 8 + 4 + 4);
1446 break;
1447 }
1448 case TYPE_TURN_RATE:
1449 {
1450 data.Initialize(MSG_MOVE_SET_TURN_RATE, 1 + 8 + 4 + 4);
1452 break;
1453 }
1454 case TYPE_FLY:
1455 {
1456 data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 1 + 8 + 4 + 4);
1457#if VERSION_STRING == Mop
1458 data << float(speed);
1459 data << uint32_t(0);
1460
1461 data.writeBit(guid[6]);
1462 data.writeBit(guid[5]);
1463 data.writeBit(guid[0]);
1464 data.writeBit(guid[4]);
1465 data.writeBit(guid[1]);
1466 data.writeBit(guid[7]);
1467 data.writeBit(guid[3]);
1468 data.writeBit(guid[2]);
1469
1470 data.WriteByteSeq(guid[0]);
1471 data.WriteByteSeq(guid[7]);
1472 data.WriteByteSeq(guid[4]);
1473 data.WriteByteSeq(guid[5]);
1474 data.WriteByteSeq(guid[6]);
1475 data.WriteByteSeq(guid[2]);
1476 data.WriteByteSeq(guid[3]);
1477 data.WriteByteSeq(guid[1]);
1478#else
1480#endif
1481 break;
1482 }
1483 case TYPE_FLY_BACK:
1484 {
1485 data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 1 + 8 + 4 + 4);
1487 break;
1488 }
1489 case TYPE_PITCH_RATE:
1490 {
1491 data.Initialize(MSG_MOVE_SET_PITCH_RATE, 1 + 8 + 4 + 4);
1493 break;
1494 }
1495 }
1496
1497 sendMessageToSet(&data, true);
1498}
1499#endif
1500
1502{
1503 if (m_resendSpeed)
1504 {
1507 m_resendSpeed = false;
1508 }
1509}
1510bool Player::isMoving() const { return m_isMoving; }
1511
1514
1515bool Player::isOnVehicle() const { return m_mountVehicleId ? true : false; }
1518
1520{
1521 uint32_t auraInterruptFlags = 0;
1522 if (movementInfo.hasMovementFlag(MOVEFLAG_MOTION_MASK))
1523 auraInterruptFlags |= AURA_INTERRUPT_ON_MOVEMENT;
1524
1525 if (!(movementInfo.hasMovementFlag(MOVEFLAG_SWIMMING)) || movementInfo.hasMovementFlag(MOVEFLAG_FALLING))
1526 auraInterruptFlags |= AURA_INTERRUPT_ON_LEAVE_WATER;
1527
1528 if (movementInfo.hasMovementFlag(MOVEFLAG_SWIMMING))
1529 auraInterruptFlags |= AURA_INTERRUPT_ON_ENTER_WATER;
1530
1531 if ((movementInfo.hasMovementFlag(MOVEFLAG_TURNING_MASK)) || m_isTurning)
1532 auraInterruptFlags |= AURA_INTERRUPT_ON_TURNING;
1533
1534 removeAllAurasByAuraInterruptFlag(auraInterruptFlags);
1535}
1536
1538{
1539 if (const auto at = GetArea())
1540 {
1541 ::WDB::Structures::AreaTableEntry const* zt = nullptr;
1542 if (at->zone)
1544
1547
1548 return (areaIsCity || zoneIsCity);
1549 }
1550
1551 return false;
1552}
1553
1554void Player::handleBreathing(MovementInfo const& movementInfo, WorldSession* session)
1555{
1557 {
1559 m_underwaterState &= ~UNDERWATERSTATE_SWIMMING;
1560
1562 {
1563 m_underwaterState &= ~UNDERWATERSTATE_UNDERWATER;
1565 }
1566
1567 if (session->m_bIsWLevelSet)
1568 {
1569 if (movementInfo.getPosition()->z + m_noseLevel > session->m_wLevel)
1570 {
1572 session->m_bIsWLevelSet = false;
1573 }
1574 }
1575
1576 return;
1577 }
1578
1580 {
1582
1583 if (!session->m_bIsWLevelSet)
1584 {
1585 session->m_wLevel = movementInfo.getPosition()->z + m_noseLevel * 0.95f;
1586 session->m_bIsWLevelSet = true;
1587 }
1588
1590 }
1591
1592#if VERSION_STRING <= WotLK
1594#else
1596#endif
1597 {
1598 if (movementInfo.getPosition()->z + m_noseLevel > session->m_wLevel)
1599 {
1601 session->m_bIsWLevelSet = false;
1602
1603 m_underwaterState &= ~UNDERWATERSTATE_SWIMMING;
1604 }
1605 }
1606
1608 {
1609 if (movementInfo.getPosition()->z + m_noseLevel < session->m_wLevel)
1610 {
1613 }
1614 }
1615
1617 {
1618 if (movementInfo.getPosition()->z + m_noseLevel > session->m_wLevel)
1619 {
1620 m_underwaterState &= ~UNDERWATERSTATE_UNDERWATER;
1622 }
1623 }
1624
1626 {
1627 if (movementInfo.getPosition()->z + m_noseLevel > session->m_wLevel)
1628 {
1629 m_underwaterState &= ~UNDERWATERSTATE_UNDERWATER;
1631 }
1632 }
1633}
1634
1635//\todo: find another solution for this
1637{
1638 // Set the height of the player
1639 switch (getRace())
1640 {
1641 case RACE_HUMAN:
1642 // female
1643 if (getGender())
1644 m_noseLevel = 1.72f;
1645 // male
1646 else
1647 m_noseLevel = 1.78f;
1648 break;
1649 case RACE_ORC:
1650 if (getGender())
1651 m_noseLevel = 1.82f;
1652 else
1653 m_noseLevel = 1.98f;
1654 break;
1655 case RACE_DWARF:
1656 if (getGender())
1657 m_noseLevel = 1.27f;
1658 else
1659 m_noseLevel = 1.4f;
1660 break;
1661 case RACE_NIGHTELF:
1662 if (getGender())
1663 m_noseLevel = 1.84f;
1664 else
1665 m_noseLevel = 2.13f;
1666 break;
1667 case RACE_UNDEAD:
1668 if (getGender())
1669 m_noseLevel = 1.61f;
1670 else
1671 m_noseLevel = 1.8f;
1672 break;
1673 case RACE_TAUREN:
1674 if (getGender())
1675 m_noseLevel = 2.48f;
1676 else
1677 m_noseLevel = 2.01f;
1678 break;
1679 case RACE_GNOME:
1680 if (getGender())
1681 m_noseLevel = 1.06f;
1682 else
1683 m_noseLevel = 1.04f;
1684 break;
1685#if VERSION_STRING >= Cata
1686 case RACE_GOBLIN:
1687 if (getGender())
1688 m_noseLevel = 1.06f;
1689 else
1690 m_noseLevel = 1.04f;
1691 break;
1692#endif
1693 case RACE_TROLL:
1694 if (getGender())
1695 m_noseLevel = 2.02f;
1696 else
1697 m_noseLevel = 1.93f;
1698 break;
1699#if VERSION_STRING > Classic
1700 case RACE_BLOODELF:
1701 if (getGender())
1702 m_noseLevel = 1.83f;
1703 else
1704 m_noseLevel = 1.93f;
1705 break;
1706 case RACE_DRAENEI:
1707 if (getGender())
1708 m_noseLevel = 2.09f;
1709 else
1710 m_noseLevel = 2.36f;
1711 break;
1712#endif
1713#if VERSION_STRING >= Cata
1714 case RACE_WORGEN:
1715 if (getGender())
1716 m_noseLevel = 1.72f;
1717 else
1718 m_noseLevel = 1.78f;
1719 break;
1720#endif
1721 }
1722}
1723
1724void Player::handleKnockback(Object* object, float horizontal, float vertical)
1725{
1726 if (object == nullptr)
1727 object = this;
1728
1729 float angle = calcRadAngle(object->GetPositionX(), object->GetPositionY(), GetPositionX(), GetPositionY());
1730 if (object == this)
1731 angle = static_cast<float>(M_PI + GetOrientation());
1732
1733 float sin = sinf(angle);
1734 float cos = cosf(angle);
1735
1736 getSession()->SendPacket(SmsgMoveKnockBack(GetNewGUID(), Util::getMSTime(), cos, sin, horizontal, -vertical).serialise().get());
1737
1738 m_blinked = true;
1739 speedCheatDelay(10000);
1740}
1741
1743{
1744 if (map)
1745 {
1746 if (map->getPlayer(this->getGuidLow()))
1747 {
1748 this->SetPosition(vec);
1749 }
1750 else
1751 {
1752 if (map->getBaseMap()->getMapId() == 530 && !this->getSession()->HasFlag(ACCOUNT_FLAG_XPACK_01))
1753 return false;
1754
1755 if (map->getBaseMap()->getMapId() == 571 && !this->getSession()->HasFlag(ACCOUNT_FLAG_XPACK_02))
1756 return false;
1757
1758 this->safeTeleport(map, vec);
1759 }
1760
1761 return true;
1762 }
1763
1764 return false;
1765}
1766
1768{
1769 safeTeleport(mapId, instanceId, position);
1770}
1771
1773{
1774 // do not teleport to an unallowed mapId
1775 if (const auto mapInfo = sMySQLStore.getWorldMapInfo(mapId))
1776 {
1778 {
1780 return false;
1781 }
1782
1784 {
1786 return false;
1787 }
1788 }
1789
1790 // hide waypoints otherwise it will crash when trying to unload map
1791 if (m_aiInterfaceWaypoint != nullptr)
1793
1794 m_aiInterfaceWaypoint = nullptr;
1795
1796 speedCheatDelay(10000);
1797
1798 if (m_taxi->getCurrentTaxiPath())
1799 {
1800 sEventMgr.RemoveEvents(this, EVENT_PLAYER_TELEPORT);
1802
1805
1807 }
1808
1810 {
1811 if (const auto transporter = sTransportHandler.getTransporter(WoWGuid::getGuidLowPartFromUInt64(obj_movement_info.transport_guid)))
1812 {
1813 transporter->RemovePassenger(this);
1815 }
1816 }
1817
1818 bool instance = false;
1819 if (instanceId && static_cast<uint32_t>(m_instanceId) != instanceId)
1820 {
1821 instance = true;
1822 this->SetInstanceID(instanceId);
1823 }
1824 else if (m_mapId != mapId)
1825 {
1826 instance = true;
1827 }
1828
1829 // make sure player does not drown when teleporting from under water
1831 m_underwaterState &= ~UNDERWATERSTATE_UNDERWATER;
1832
1833 // can only fly in outlands or northrend (northrend requires cold weather flying)
1834 if (m_flyingAura && ((m_mapId != 530) && (m_mapId != 571 || !hasSpell(54197) && getDeathState() == ALIVE)))
1835 {
1837 m_flyingAura = 0;
1838 }
1839
1840#ifdef FT_VEHICLES
1841 callExitVehicle();
1842#endif
1843
1844 if (m_bg && m_bg->getWorldMap() && getWorldMap() && getWorldMap()->getBaseMap()->getMapInfo()->mapid != mapId)
1845 {
1846 m_bg->removePlayer(this, false);
1847 }
1848
1849 _Relocate(mapId, vec, true, instance, instanceId);
1850
1852
1854
1855 return true;
1856}
1857
1859{
1860 if (mgr)
1861 {
1862 speedCheatDelay(10000);
1863
1864 // can only fly in outlands or northrend (northrend requires cold weather flying)
1865 if (m_flyingAura && ((m_mapId != 530) && (m_mapId != 571 || !hasSpell(54197) && getDeathState() == ALIVE)))
1866 {
1868 m_flyingAura = 0;
1869 }
1870
1871 if (IsInWorld())
1873
1874 m_mapId = mgr->getBaseMap()->getMapId();
1875 m_instanceId = mgr->getInstanceId();
1876
1879
1883
1886 }
1887}
1888
1892
1894
1896{
1897#if VERSION_STRING < Cata
1898 WorldPacket data2(MSG_MOVE_TELEPORT, 38);
1899 data2.append(GetNewGUID());
1900 buildMovementPacket(&data2, position.x, position.y, position.z, position.o);
1901 sendMessageToSet(&data2, false);
1902 SetPosition(position);
1903#else
1905 LocationVector pos = position;
1906
1908 SetPosition(pos);
1909
1910 ObjectGuid guid = getGuid();
1911
1914
1916 {
1917 WorldPacket data2(MSG_MOVE_TELEPORT, 38);
1918 data2.writeBit(guid[6]);
1919 data2.writeBit(guid[0]);
1920 data2.writeBit(guid[3]);
1921 data2.writeBit(guid[2]);
1922 data2.writeBit(0); // unk
1923 //\TODO add transport
1924 data2.writeBit(uint64_t(0)); // transport guid
1925 data2.writeBit(guid[1]);
1926
1927 data2.writeBit(guid[4]);
1928 data2.writeBit(guid[7]);
1929 data2.writeBit(guid[5]);
1930 data2.flushBits();
1931
1932 data2 << uint32_t(0); // unk
1933 data2.WriteByteSeq(guid[1]);
1934 data2.WriteByteSeq(guid[2]);
1935 data2.WriteByteSeq(guid[3]);
1936 data2.WriteByteSeq(guid[5]);
1937 data2 << float(GetPositionX());
1938 data2.WriteByteSeq(guid[4]);
1939 data2 << float(GetOrientation());
1940 data2.WriteByteSeq(guid[7]);
1941 data2 << float(GetPositionZ());
1942 data2.WriteByteSeq(guid[0]);
1943 data2.WriteByteSeq(guid[6]);
1944 data2 << float(GetPositionY());
1945 sendPacket(&data2);
1946 }
1947
1949 SetPosition(pos);
1950 else
1951 SetPosition(oldPos);
1952
1953 sendMessageToSet(&data, false);
1954#endif
1955}
1956
1958{
1960
1961#if VERSION_STRING < TBC
1963 data << GetNewGUID();
1964 data << uint32_t(2);
1965 data << uint32_t(0);
1966 data << uint8_t(0);
1967
1968 data << float(0);
1969 data << position.x;
1970 data << position.y;
1971 data << position.z;
1972 data << position.o;
1973 data << uint16_t(2);
1974 data << uint8_t(0);
1975#else
1977 data << GetNewGUID();
1978 data << uint32_t(0);
1979 buildMovementPacket(&data, position.x, position.y, position.z, position.o);
1980#endif
1981 getSession()->SendPacket(&data);
1982
1983#if VERSION_STRING == TBC
1984 sendTeleportPacket(position);
1985#endif
1986
1987}
1988
1990{
1991 WDB::Structures::MapEntry const* mEntry = sMapStore.lookupEntry(GetMapId());
1992 //only resurrect if player is porting to a instance portal
1993 if (mEntry->isInstanceMap() && isDead())
1994 resurrect();
1995
1996 if (mEntry->isInstanceMap())
1997 {
1998 // check if this instance has a reset time and send it to player if so
2000 if (WDB::Structures::MapDifficulty const* mapDiff = getMapDifficultyData(mEntry->id, diff))
2001 {
2002 if (mapDiff->resetTime)
2003 {
2004 if (time_t timeReset = sInstanceMgr.getResetTimeFor(static_cast<uint16_t>(mEntry->id), diff))
2005 {
2006 const auto now = Util::getTimeNow();
2007
2008 uint32_t timeleft = static_cast<uint32_t>(timeReset - now);
2009 sendInstanceResetWarning(mEntry->id, diff, timeleft, true);
2010 }
2011 }
2012 }
2013 }
2014
2016}
2017
2019{
2020 safeTeleport(gmPlayer->GetMapId(), gmPlayer->GetInstanceID(), gmPlayer->GetPosition());
2021}
2022
2024{
2025 if (worldConfig.terrainCollision.isCollisionEnabled)
2026 {
2027 if (time >= m_indoorCheckTimer)
2028 {
2029 if (!isOutdoors())
2030 {
2031 // this is duplicated check, but some mount auras comes w/o this flag set, maybe due to spellfixes.cpp line:663
2032 if (isMounted() && !m_taxi->getCurrentTaxiPath())
2033 dismount();
2034
2036 {
2037 auto* const aur = getAuraWithAuraSlot(x);
2038 if (aur && aur->getSpellInfo()->getAttributes() & ATTRIBUTES_ONLY_OUTDOORS)
2039 aur->removeAura();
2040 }
2041 }
2043 }
2044 }
2045}
2046
2049
2051{
2052 if (IS_INSTANCE(GetMapId()))
2053 return;
2054
2055 if (MySQLStructure::MapInfo const* mapInfo = sMySQLStore.getWorldMapInfo(mapId))
2056 setBGEntryPoint(mapInfo->repopx, mapInfo->repopy, mapInfo->repopz, GetOrientation(), mapInfo->repopmapid, GetInstanceID());
2057 else
2058 setBGEntryPoint(0, 0, 0, 0, 0, 0);
2059}
2060
2061//////////////////////////////////////////////////////////////////////////////////////////
2062// Instance, Zone, Area, Phase
2063void Player::setPhase(uint8_t command, uint32_t newPhase)
2064{
2065 Unit::setPhase(command, newPhase);
2066
2067 if (getSession())
2068 {
2069#if VERSION_STRING == WotLK
2070 sendPacket(SmsgPhaseShiftChange(newPhase, getGuid()).serialise().get());
2071#elif VERSION_STRING > WotLK
2072
2073 uint32_t phaseFlags = 0;
2074
2075 for (uint32_t i = 0; i < sPhaseStore.getNumRows(); ++i)
2076 {
2077 if (WDB::Structures::PhaseEntry const* phase = sPhaseStore.lookupEntry(i))
2078 {
2079 if (phase->PhaseShift == newPhase)
2080 {
2081 phaseFlags = phase->Flags;
2082 break;
2083 }
2084 }
2085 }
2086
2087 sendPacket(SmsgPhaseShiftChange(newPhase, getGuid(), phaseFlags, GetMapId()).serialise().get());
2088#endif
2089 }
2090
2091 getSummonInterface()->setPhase(command, newPhase);
2092
2093 if (Unit* charm = m_WorldMap->getUnit(getCharmGuid()))
2094 charm->setPhase(command, newPhase);
2095}
2096
2098{
2099 uint32_t oldzone = m_zoneId;
2100 if (m_zoneId != zoneId)
2101 {
2102 setZoneId(zoneId);
2104 }
2105
2106 if (m_playerInfo)
2107 {
2108 m_playerInfo->lastZone = zoneId;
2109 sHookInterface.OnZone(this, zoneId, oldzone);
2110
2112 m_WorldMap->getScript()->OnZoneChange(this, zoneId, oldzone);
2113
2114 auto at = GetArea();
2115 if (at && (at->team == AREAC_SANCTUARY || at->flags & AREA_SANCTUARY))
2116 {
2117 Unit* pUnit = (getTargetGuid() == 0) ? nullptr : (m_WorldMap ? m_WorldMap->getUnit(getTargetGuid()) : nullptr);
2118 if (pUnit && m_duelPlayer != pUnit)
2119 {
2121 smsg_AttackStop(pUnit);
2122 }
2123
2124 if (isCastingSpell())
2125 {
2126 for (uint8_t i = 0; i < CURRENT_SPELL_MAX; ++i)
2127 {
2128 if (getCurrentSpell(CurrentSpellType(i)) != nullptr)
2129 {
2131 if (target != nullptr && target != m_duelPlayer && target != this)
2132 {
2134 }
2135 }
2136 }
2137 }
2138 }
2139
2141
2143 }
2144 else
2145 {
2146 sLogger.failure("Player with invalid player_info tries to call Player::zoneUpdate()!");
2148 }
2149}
2150
2152{
2153 if (!m_WorldMap)
2154 return;
2155
2156 if (auto areaTableEntry = this->GetArea())
2157 {
2158 if (areaTableEntry->zone && areaTableEntry->zone != m_zoneId)
2159 zoneUpdate(areaTableEntry->zone);
2160
2162 }
2163}
2164
2166{
2167 if (areaTableEntry)
2168 {
2169 uint16_t offset = static_cast<uint16_t>(areaTableEntry->explore_flag / 32);
2170
2171 uint32_t val = (uint32_t)(1 << (areaTableEntry->explore_flag % 32));
2172 uint32_t currFields = getExploredZone(offset);
2173
2174 return (currFields & val) != 0;
2175 }
2176
2177 return false;
2178}
2179
2181{
2182 if (auto overlay = sWorldMapOverlayStore.lookupEntry(overlayId))
2183 {
2184 if (overlay->areaID && hasAreaExplored(AreaStorage::GetAreaById(overlay->areaID)))
2185 return true;
2186
2187 if (overlay->areaID_2 && hasAreaExplored(AreaStorage::GetAreaById(overlay->areaID_2)))
2188 return true;
2189
2190 if (overlay->areaID_3 && hasAreaExplored(AreaStorage::GetAreaById(overlay->areaID_3)))
2191 return true;
2192
2193 if (overlay->areaID_4 && hasAreaExplored(AreaStorage::GetAreaById(overlay->areaID_4)))
2194 return true;
2195 }
2196
2197 return false;
2198}
2199
2201{
2202 if (isDead())
2203 return;
2204
2205 if (!IsInWorld())
2206 return;
2207
2209 return;
2210
2211 if (getWorldMap()->getCellByCoords(GetPositionX(), GetPositionY()) == nullptr)
2212 return;
2213
2214 if (auto areaTableEntry = this->GetArea())
2215 {
2216 uint16_t offset = static_cast<uint16_t>(areaTableEntry->explore_flag / 32);
2217 uint32_t val = (uint32_t)(1 << (areaTableEntry->explore_flag % 32));
2218 uint32_t currFields = getExploredZone(offset);
2219
2220 if (areaTableEntry->id != m_areaId)
2221 {
2222 m_areaId = areaTableEntry->id;
2223
2224 updatePvPArea();
2226
2227 if (getGroup())
2228 getGroup()->UpdateOutOfRangePlayer(this, true, nullptr);
2229 }
2230
2231 if (areaTableEntry->zone == 0 && m_zoneId != areaTableEntry->id)
2232 zoneUpdate(areaTableEntry->id);
2233 else if (areaTableEntry->zone != 0 && m_zoneId != areaTableEntry->zone)
2234 zoneUpdate(areaTableEntry->zone);
2235
2236
2237 if (areaTableEntry->zone != 0 && m_zoneId != areaTableEntry->zone)
2238 zoneUpdate(areaTableEntry->zone);
2239
2240 bool rest_on = false;
2241
2242 if (areaTableEntry->flags & AREA_CITY_AREA || areaTableEntry->flags & AREA_CITY)
2243 {
2244 // check faction
2245 if (areaTableEntry->team == AREAC_ALLIANCE_TERRITORY && isTeamAlliance() || (areaTableEntry->team == AREAC_HORDE_TERRITORY && isTeamHorde()))
2246 rest_on = true;
2247 else if (areaTableEntry->team != AREAC_ALLIANCE_TERRITORY && areaTableEntry->team != AREAC_HORDE_TERRITORY)
2248 rest_on = true;
2249 }
2250 else
2251 {
2252 //second AT check for subzones.
2253 if (areaTableEntry->zone)
2254 {
2255 auto at2 = AreaStorage::GetAreaById(areaTableEntry->zone);
2256 if (at2 && (at2->flags & AREA_CITY_AREA || at2->flags & AREA_CITY))
2257 {
2258 if (at2->team == AREAC_ALLIANCE_TERRITORY && isTeamAlliance() || (at2->team == AREAC_HORDE_TERRITORY && isTeamHorde()))
2259 rest_on = true;
2260 else if (at2->team != AREAC_ALLIANCE_TERRITORY && at2->team != AREAC_HORDE_TERRITORY)
2261 rest_on = true;
2262 }
2263 }
2264 }
2265
2266 if (rest_on)
2267 {
2268 if (!m_isResting)
2270 }
2271 else
2272 {
2273 if (m_isResting)
2274 applyPlayerRestState(false);
2275 }
2276
2277 if (!(currFields & val) && !m_taxi->getCurrentTaxiPath() && !obj_movement_info.transport_guid)
2278 {
2279 setExploredZone(offset, currFields | val);
2280
2281 uint32_t explore_xp = areaTableEntry->area_level * 10;
2282 explore_xp *= Util::float2int32(worldConfig.getFloatRate(RATE_EXPLOREXP));
2283
2284#if VERSION_STRING > TBC
2285 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, getAreaId());
2286#endif
2287
2288 if (getLevel() < getMaxLevel() && explore_xp > 0)
2289 {
2290 sendExploreExperiencePacket(areaTableEntry->id, explore_xp);
2291 giveXp(explore_xp, 0, false);
2292 }
2293 else
2294 {
2295 sendExploreExperiencePacket(areaTableEntry->id, 0);
2296 }
2297 }
2298 }
2299}
2300
2309
2311{
2312 if (getBGEntryPosition().isSet())
2313 {
2316
2317 return true;
2318 }
2319
2320 return false;
2321}
2322
2323//////////////////////////////////////////////////////////////////////////////////////////
2324// Commands
2325void Player::disableSummoning(bool disable) { m_disableSummoning = disable; }
2327void Player::disableAppearing(bool disable) { m_disableAppearing = disable; }
2329
2331{
2332 if (m_banned)
2333 {
2334 if (m_banned < 100 || static_cast<uint32_t>(UNIXTIME) < m_banned)
2335 return true;
2336 }
2337 return false;
2338}
2339
2340void Player::setBanned(uint32_t timestamp /*= 4*/, std::string Reason /*= ""*/) { m_banned = timestamp; m_banreason = Reason; }
2342std::string Player::getBanReason() const { return m_banreason; }
2343
2345{
2346 if (m_GMSelectedGO)
2347 return getWorldMap()->getGameObject(static_cast<uint32_t>(m_GMSelectedGO));
2348
2349 return nullptr;
2350}
2351
2353
2355{
2356 if (delay)
2357 {
2358 m_kickDelay = delay;
2360 }
2361 else
2362 {
2363 m_kickDelay = 0;
2365 }
2366}
2367
2369{
2370 if (m_kickDelay)
2371 {
2372 if (m_kickDelay < 1500)
2373 m_kickDelay = 0;
2374 else
2375 m_kickDelay -= 1000;
2376
2377 getSession()->systemMessage("You will be removed from the server in {} seconds.", m_kickDelay / 1000);
2378 }
2379 else
2380 {
2381 sEventMgr.RemoveEvents(this, EVENT_PLAYER_KICK);
2382 getSession()->LogoutPlayer(true);
2383 }
2384}
2385
2386void Player::sendSummonRequest(uint32_t requesterId, uint32_t zoneId, uint32_t mapId, uint32_t instanceId, const LocationVector& position)
2387{
2388 m_summonData.instanceId = instanceId;
2389 m_summonData.position = position;
2390 m_summonData.summonerId = requesterId;
2391 m_summonData.mapId = mapId;
2392
2393 m_session->SendPacket(SmsgSummonRequest(requesterId, zoneId, 120000).serialise().get());
2394}
2395
2396void Player::setAFKReason(std::string reason) { afkReason = reason; }
2397std::string Player::getAFKReason() const { return afkReason; }
2398
2400{
2401 std::lock_guard<std::mutex> guard(m_lockGMTargetList);
2402 m_gmPlayerTargetList.push_back(guid);
2403}
2404
2406{
2407 std::lock_guard<std::mutex> guard(m_lockGMTargetList);
2408 m_gmPlayerTargetList.erase(std::remove(m_gmPlayerTargetList.begin(), m_gmPlayerTargetList.end(), guid), m_gmPlayerTargetList.end());
2409}
2410
2412{
2413 std::lock_guard<std::mutex> guard(m_lockGMTargetList);
2414 if (std::find(m_gmPlayerTargetList.begin(), m_gmPlayerTargetList.end(), guid) != m_gmPlayerTargetList.end())
2415 return true;
2416
2417 return false;
2418}
2419
2420//////////////////////////////////////////////////////////////////////////////////////////
2421// Basic
2422bool Player::create(CharCreate& charCreateContent)
2423{
2424 m_name = charCreateContent.name;
2426
2427 //\todo: Zyres: we already have a method to check if the race/class combination is valid (somewhere in the char list generation).
2428 m_playerCreateInfo = sMySQLStore.getPlayerCreateInfo(charCreateContent._race, charCreateContent._class);
2429 if (m_playerCreateInfo == nullptr)
2430 {
2432#if VERSION_STRING > TBC
2433 if (charCreateContent._class == DEATHKNIGHT)
2434 sLogger.failure("Account Name: {} tried to create a deathknight, however your playercreateinfo table does not support this class, please update your database.", m_session->GetAccountName());
2435 else
2436#endif
2437 sLogger.failure("Account Name: {} tried to create an invalid character with race {} and class {}, if this is intended please update your playercreateinfo table inside your database.", m_session->GetAccountName(), charCreateContent._race, charCreateContent._class);
2438 return false;
2439 }
2440
2441 // check that the account creates only new ones with available races, if we're making some
2442#if VERSION_STRING > Classic
2443 if (charCreateContent._race >= RACE_BLOODELF && !(m_session->_accountFlags & ACCOUNT_FLAG_XPACK_01))
2444#else
2445 if (charCreateContent._race >= RACE_TROLL)
2446#endif
2447 {
2449 return false;
2450 }
2451
2452#if VERSION_STRING > TBC
2453 // check that the account can create deathknights, if we're making one
2454 if (charCreateContent._class == DEATHKNIGHT && !(m_session->_accountFlags & ACCOUNT_FLAG_XPACK_02))
2455 {
2456 sLogger.failure("Account {} tried to create a DeathKnight, but Account flag is {}!", m_session->GetAccountName(), m_session->_accountFlags);
2458 return false;
2459 }
2460#endif
2461
2465
2467 m_isResting = 0;
2468 m_restAmount = 0;
2469 m_restState = 0;
2470
2471 // set race dbc
2472 m_dbcRace = sChrRacesStore.lookupEntry(charCreateContent._race);
2473 m_dbcClass = sChrClassesStore.lookupEntry(charCreateContent._class);
2474 if (!m_dbcRace || !m_dbcClass)
2475 {
2476 // information not found
2477 sCheatLog.writefromsession(m_session, "tried to create invalid player with race %u and class %u, dbc m_playerCreateInfo not found", charCreateContent._race, charCreateContent._class);
2479 return false;
2480 }
2481
2482 if (m_dbcRace->team_id == 7)
2483 m_team = 0;
2484 else
2485 m_team = 1;
2486
2487 // Automatically add the race's taxi hub to the character's taximask at creation time (1 << (taxi_node_id-1))
2488 // this is defined in table playercreateinfo, field taximask
2489 //memcpy(m_taxiMask, m_playerCreateInfo->taximask, sizeof(m_taxiMask));
2490
2491 if (auto playerClassLevelStats = sMySQLStore.getPlayerClassLevelStats(1, charCreateContent._class))
2492 setMaxHealth(playerClassLevelStats->health);
2493 else
2494 sLogger.failure("No class levelstats found!");
2495
2496 if (const auto raceEntry = sChrRacesStore.lookupEntry(charCreateContent._race))
2497 setFaction(raceEntry->faction_id);
2498 else
2499 setFaction(0);
2500
2501#if VERSION_STRING > TBC
2502 if (charCreateContent._class != DEATHKNIGHT || worldConfig.player.playerStartingLevel > 55)
2503#endif
2504 {
2505 setLevel(worldConfig.player.playerStartingLevel);
2506 }
2507#if VERSION_STRING > TBC
2508 else
2509 {
2510 setLevel(55);
2511 }
2512#endif
2513
2514 setRace(charCreateContent._race);
2515 setClass(charCreateContent._class);
2516 setGender(charCreateContent.gender);
2517
2519 setInitialDisplayIds(charCreateContent.gender, charCreateContent._race);
2520
2522
2523 // PLAYER_BYTES
2524 setSkinColor(charCreateContent.skin);
2525 setFace(charCreateContent.face);
2526 setHairStyle(charCreateContent.hairStyle);
2527 setHairColor(charCreateContent.hairColor);
2528
2529 // PLAYER_BYTES_2
2530 setPlayerBytes2(0);
2531 setFacialFeatures(charCreateContent.facialHair);
2533
2534 // PLAYER_BYTES_3
2535 setPlayerBytes3(0);
2536 setPlayerGender(charCreateContent.gender);
2537
2539
2540 // Gold Starting Amount
2541 setCoinage(worldConfig.player.startGoldAmount);
2542
2543 // Default value is -1
2544 setWatchedFaction(std::numeric_limits<uint32_t>::max());
2545
2546 // Profession points
2547 setFreePrimaryProfessionPoints(worldConfig.player.maxProfessions);
2548
2550
2551 m_firstLogin = true;
2552
2553 // add dbc items
2554 if (const auto charStartOutfitEntry = getStartOutfitByRaceClass(charCreateContent._race, charCreateContent._class, charCreateContent.gender))
2555 {
2556 for (uint8_t j = 0; j < OUTFIT_ITEMS; ++j)
2557 {
2558 if (charStartOutfitEntry->ItemId[j] <= 0)
2559 continue;
2560
2561 const uint32_t itemId = charStartOutfitEntry->ItemId[j];
2562
2563 const auto itemProperties = sMySQLStore.getItemProperties(itemId);
2564 if (!itemProperties)
2565 {
2566 sLogger.debug("StartOutfit - Item with entry {} not in item_properties table but in CharStartOutfit.dbc!", itemId);
2567 continue;
2568 }
2569
2570 auto item = sObjectMgr.createItem(itemId, this);
2571 if (item)
2572 {
2573 item->setStackCount(1);
2574
2575 int8_t itemSlot = 0;
2576
2577 //shitty db lets check for dbc/db2 values
2578 if (itemProperties->InventoryType == 0)
2579 {
2580 if (const auto itemDB2Properties = sItemStore.lookupEntry(itemId))
2581 itemSlot = getItemInterface()->GetItemSlotByType(itemDB2Properties->InventoryType);
2582 }
2583 else
2584 {
2585 itemSlot = getItemInterface()->GetItemSlotByType(itemProperties->InventoryType);
2586 }
2587
2588 //use safeadd only for equipmentset items... all other items will go to a free bag slot.
2589 if (itemSlot < INVENTORY_SLOT_BAG_END && (itemProperties->Class == ITEM_CLASS_ARMOR || itemProperties->Class == ITEM_CLASS_WEAPON || itemProperties->Class == ITEM_CLASS_CONTAINER || itemProperties->Class == ITEM_CLASS_QUIVER))
2590 {
2591 const auto [addResult, _] = getItemInterface()->SafeAddItem(std::move(item), INVENTORY_SLOT_NOT_SET, itemSlot);
2592 if (!addResult)
2593 {
2594 sLogger.debug("StartOutfit - Item with entry {} can not be added safe to slot {}!", itemId, static_cast<uint32_t>(itemSlot));
2595 }
2596 }
2597 else
2598 {
2599 item->setStackCount(itemProperties->MaxCount);
2600 const auto [addResult, _] = getItemInterface()->AddItemToFreeSlot(std::move(item));
2601 if (!addResult)
2602 {
2603 sLogger.debug("StartOutfit - Item with entry {} can not be added to a free slot!", itemId);
2604 }
2605 }
2606 }
2607 }
2608 }
2609
2610 for (std::list<CreateInfo_ItemStruct>::const_iterator is = m_playerCreateInfo->items.begin(); is != m_playerCreateInfo->items.end(); ++is)
2611 {
2612 if ((*is).id != 0)
2613 {
2614 auto item = sObjectMgr.createItem((*is).id, this);
2615 if (item)
2616 {
2617 item->setStackCount((*is).amount);
2618 if ((*is).slot < INVENTORY_SLOT_BAG_END)
2619 {
2620 getItemInterface()->SafeAddItem(std::move(item), INVENTORY_SLOT_NOT_SET, (*is).slot);
2621 }
2622 else
2623 {
2624 getItemInterface()->AddItemToFreeSlot(std::move(item));
2625 }
2626 }
2627 }
2628 }
2629
2630 sHookInterface.OnCharacterCreate(this);
2633 return true;
2634}
2635
2638
2640void Player::setName(utf8_string name) { m_name = name; }
2641
2644
2646{
2647 if (const auto raceEntry = sChrRacesStore.lookupEntry(race))
2648 {
2649 switch (gender)
2650 {
2651 case GENDER_MALE:
2652 setDisplayId(raceEntry->model_male);
2653 setNativeDisplayId(raceEntry->model_male);
2654 break;
2655 case GENDER_FEMALE:
2656 setDisplayId(raceEntry->model_female);
2657 setNativeDisplayId(raceEntry->model_female);
2658 break;
2659 default:
2660 sLogger.failure("Gender {} is not valid for Player charecters!", gender);
2661 }
2662 }
2663 else
2664 {
2665 sLogger.failure("Race {} is not supported by this AEVersion ({})", race, getAEVersion());
2666 }
2667}
2668
2670{
2671 const auto previousLevel = getLevel();
2672
2673 if (!m_firstLogin)
2674 {
2675 const auto previousLevelInfo = m_levelInfo;
2676
2677 m_levelInfo = sObjectMgr.getLevelInfo(getRace(), getClass(), newLevel);
2678 if (m_levelInfo == nullptr)
2679 return;
2680
2681 if (isDead())
2682 resurrect();
2683
2684 setLevel(newLevel);
2685
2688
2689 for (uint8_t i = 0; i < STAT_COUNT; ++i)
2690 {
2691 m_baseStats[i] = m_levelInfo->Stat[i];
2692 calcStat(i);
2693 }
2694
2695#if VERSION_STRING >= WotLK
2696 for (uint8_t i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
2697 if (Item* pItem = getItemInterface()->GetInventoryItem(i))
2698 applyItemMods(pItem, i, true, false, true);
2699#endif
2700 updateStats();
2701
2703
2707#if VERSION_STRING >= WotLK
2709#endif
2710
2712 newLevel,
2713 m_levelInfo->HP - previousLevelInfo->HP,
2714 m_levelInfo->Mana - previousLevelInfo->Mana,
2715 m_levelInfo->Stat[STAT_STRENGTH] - previousLevelInfo->Stat[STAT_STRENGTH],
2716 m_levelInfo->Stat[STAT_AGILITY] - previousLevelInfo->Stat[STAT_AGILITY],
2717 m_levelInfo->Stat[STAT_STAMINA] - previousLevelInfo->Stat[STAT_STAMINA],
2718 m_levelInfo->Stat[STAT_INTELLECT] - previousLevelInfo->Stat[STAT_INTELLECT],
2719 m_levelInfo->Stat[STAT_SPIRIT] - previousLevelInfo->Stat[STAT_SPIRIT]);
2720 }
2721
2722#if VERSION_STRING >= TBC
2723 // Classic does not have any level dependant flight paths
2725#endif
2726
2728
2729 if (newLevel > previousLevel || m_firstLogin)
2731 else if (newLevel != previousLevel)
2733
2734 m_playerInfo->lastLevel = previousLevel;
2735
2736#if VERSION_STRING >= WotLK
2737 updateGlyphs();
2738 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
2739#endif
2740
2741 if (m_firstLogin)
2742 sHookInterface.OnFirstEnterWorld(this);
2743 else
2744 sHookInterface.OnPostLevelUp(this);
2745
2746 if (getClass() == WARLOCK)
2747 {
2748 const auto pet = getPet();
2749 if (pet != nullptr && pet->IsInWorld() && pet->isAlive())
2750 {
2751 pet->setLevel(newLevel);
2752 pet->applyStatsForLevel();
2753 pet->updateSpellList();
2754 }
2755 }
2756
2757 smsg_TalentsInfo(false);
2758
2759 m_playedTime[0] = 0;
2760}
2761
2762bool Player::isClassMage() const { return false; }
2763bool Player::isClassDeathKnight() const { return false; }
2764bool Player::isClassPriest() const { return false; }
2765bool Player::isClassRogue() const { return false; }
2766bool Player::isClassShaman() const { return false; }
2767bool Player::isClassHunter() const { return false; }
2768bool Player::isClassWarlock() const { return false; }
2769bool Player::isClassWarrior() const { return false; }
2770bool Player::isClassPaladin() const { return false; }
2771bool Player::isClassMonk() const { return false; }
2772bool Player::isClassDruid() const { return false; }
2773
2776void Player::setTeam(uint32_t team) { m_team = team; m_bgTeam = team; }
2778
2780
2786
2787bool Player::isTeamHorde() const { return getTeam() == TEAM_HORDE; }
2788bool Player::isTeamAlliance() const { return getTeam() == TEAM_ALLIANCE; }
2789
2791{
2792 if (getCharmedByGuid() != 0)
2794
2795 return nullptr;
2796}
2797
2799{
2800 if (getCharmedByGuid() != 0)
2802
2803 return nullptr;
2804}
2805
2807{
2808 if (auto* const unitOwner = getUnitOwner())
2809 return unitOwner;
2810
2811 return this;
2812}
2813
2815{
2816 if (auto* const unitOwner = getUnitOwner())
2817 return unitOwner;
2818
2819 return this;
2820}
2821
2823{
2824 if (getCharmedByGuid() != 0)
2826
2827 return nullptr;
2828}
2829
2831{
2832 if (getCharmedByGuid() != 0)
2834
2835 return nullptr;
2836}
2837
2839{
2840 if (auto* const plrOwner = getPlayerOwner())
2841 return plrOwner;
2842
2843 return this;
2844}
2845
2847{
2848 if (auto* const plrOwner = getPlayerOwner())
2849 return plrOwner;
2850
2851 return this;
2852}
2853
2855{
2857 {
2859 if (worldConfig.getKickAFKPlayerTime())
2860 sEventMgr.RemoveEvents(this, EVENT_PLAYER_SOFT_DISCONNECT);
2861 }
2862 else
2863 {
2865
2866 if (m_bg)
2867 m_bg->removePlayer(this, false);
2868
2869 if (worldConfig.getKickAFKPlayerTime())
2871 worldConfig.getKickAFKPlayerTime(), 1, 0);
2872 }
2873}
2874
2882
2884
2886
2887void Player::changeLooks(uint64_t guid, uint8_t gender, uint8_t skin, uint8_t face, uint8_t hairStyle, uint8_t hairColor, uint8_t facialHair)
2888{
2889 auto result = CharacterDatabase.Query("SELECT bytes2 FROM `characters` WHERE guid = '%u'", static_cast<uint32_t>(guid));
2890 if (!result)
2891 return;
2892
2893 Field* fields = result->Fetch();
2894
2895 uint32_t player_bytes2 = fields[0].asUint32();
2896 player_bytes2 &= ~0xFF;
2897 player_bytes2 |= facialHair;
2898
2899 CharacterDatabase.Execute("UPDATE `characters` SET gender = '%u', bytes = '%u', bytes2 = '%u' WHERE guid = '%u'", gender, skin | (face << 8) | (hairStyle << 16) | (hairColor << 24), player_bytes2, (uint32_t)guid);
2900}
2901
2903{
2904 const auto getSpellIdForLanguage = [](uint16_t skillId) -> uint32_t
2905 {
2906 switch (skillId)
2907 {
2908 case SKILL_LANG_COMMON:
2909 return 668;
2910 case SKILL_LANG_ORCISH:
2911 return 669;
2912 case SKILL_LANG_TAURAHE:
2913 return 670;
2915 return 671;
2916 case SKILL_LANG_DWARVEN:
2917 return 672;
2919 return 813;
2921 return 814;
2923 return 815;
2924 case SKILL_LANG_TITAN:
2925 return 816;
2927 return 817;
2928 case SKILL_LANG_GNOMISH:
2929 return 7340;
2930 case SKILL_LANG_TROLL:
2931 return 7341;
2933 return 17737;
2934#if VERSION_STRING >= TBC
2935 case SKILL_LANG_DRAENEI:
2936 return 29932;
2937#endif
2938#if VERSION_STRING >= Cata
2939 case SKILL_LANG_GOBLIN:
2940 return 69269;
2941 case SKILL_LANG_GILNEAN:
2942 return 69270;
2943#endif
2944#if VERSION_STRING >= Mop
2946 return 108127;
2948 return 108130;
2950 return 108131;
2951#endif
2952 }
2953
2954 return 0;
2955 };
2956
2957#if VERSION_STRING < TBC
2958 CharacterDatabase.Execute("DELETE FROM `playerspells` WHERE GUID = '%u' AND SpellID IN ('%u', '%u', '%u', '%u', '%u','%u', '%u', '%u', '%u');", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH), getSpellIdForLanguage(SKILL_LANG_TAURAHE), getSpellIdForLanguage(SKILL_LANG_TROLL), getSpellIdForLanguage(SKILL_LANG_GUTTERSPEAK), getSpellIdForLanguage(SKILL_LANG_THALASSIAN), getSpellIdForLanguage(SKILL_LANG_COMMON), getSpellIdForLanguage(SKILL_LANG_DARNASSIAN), getSpellIdForLanguage(SKILL_LANG_DWARVEN), getSpellIdForLanguage(SKILL_LANG_GNOMISH));
2959#elif VERSION_STRING < Cata
2960 CharacterDatabase.Execute("DELETE FROM `playerspells` WHERE GUID = '%u' AND SpellID IN ('%u', '%u', '%u', '%u', '%u','%u', '%u', '%u', '%u', '%u');", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH), getSpellIdForLanguage(SKILL_LANG_TAURAHE), getSpellIdForLanguage(SKILL_LANG_TROLL), getSpellIdForLanguage(SKILL_LANG_GUTTERSPEAK), getSpellIdForLanguage(SKILL_LANG_THALASSIAN), getSpellIdForLanguage(SKILL_LANG_COMMON), getSpellIdForLanguage(SKILL_LANG_DARNASSIAN), getSpellIdForLanguage(SKILL_LANG_DRAENEI), getSpellIdForLanguage(SKILL_LANG_DWARVEN), getSpellIdForLanguage(SKILL_LANG_GNOMISH));
2961#elif VERSION_STRING == Cata
2962 CharacterDatabase.Execute("DELETE FROM `playerspells` WHERE GUID = '%u' AND SpellID IN ('%u', '%u', '%u', '%u', '%u','%u', '%u', '%u', '%u', '%u');", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH), getSpellIdForLanguage(SKILL_LANG_TAURAHE), getSpellIdForLanguage(SKILL_LANG_TROLL), getSpellIdForLanguage(SKILL_LANG_GUTTERSPEAK), getSpellIdForLanguage(SKILL_LANG_THALASSIAN), getSpellIdForLanguage(SKILL_LANG_COMMON), getSpellIdForLanguage(SKILL_LANG_DARNASSIAN), getSpellIdForLanguage(SKILL_LANG_DRAENEI), getSpellIdForLanguage(SKILL_LANG_DWARVEN), getSpellIdForLanguage(SKILL_LANG_GNOMISH), getSpellIdForLanguage(SKILL_LANG_GILNEAN), getSpellIdForLanguage(SKILL_LANG_GOBLIN));
2963#elif VERSION_STRING == Mop
2964 CharacterDatabase.Execute("DELETE FROM `playerspells` WHERE GUID = '%u' AND SpellID IN ('%u', '%u', '%u', '%u', '%u','%u', '%u', '%u', '%u', '%u');", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH), getSpellIdForLanguage(SKILL_LANG_TAURAHE), getSpellIdForLanguage(SKILL_LANG_TROLL), getSpellIdForLanguage(SKILL_LANG_GUTTERSPEAK), getSpellIdForLanguage(SKILL_LANG_THALASSIAN), getSpellIdForLanguage(SKILL_LANG_COMMON), getSpellIdForLanguage(SKILL_LANG_DARNASSIAN), getSpellIdForLanguage(SKILL_LANG_DRAENEI), getSpellIdForLanguage(SKILL_LANG_DWARVEN), getSpellIdForLanguage(SKILL_LANG_GNOMISH), getSpellIdForLanguage(SKILL_LANG_GILNEAN), getSpellIdForLanguage(SKILL_LANG_GOBLIN), getSpellIdForLanguage(SKILL_LANG_PANDAREN_NEUTRAL), getSpellIdForLanguage(SKILL_LANG_PANDAREN_ALLIANCE), getSpellIdForLanguage(SKILL_LANG_PANDAREN_HORDE));
2965#endif
2966 switch (race)
2967 {
2968 case RACE_DWARF:
2969 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
2970 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_DWARVEN));
2971 break;
2972#if VERSION_STRING > Classic
2973 case RACE_DRAENEI:
2974 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
2975 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_DRAENEI));
2976 break;
2977#endif
2978 case RACE_GNOME:
2979 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
2980 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_GNOMISH));
2981 break;
2982 case RACE_NIGHTELF:
2983 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
2984 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_DARNASSIAN));
2985 break;
2986 case RACE_UNDEAD:
2987 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
2988 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_GUTTERSPEAK));
2989 break;
2990 case RACE_TAUREN:
2991 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
2992 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_TAURAHE));
2993 break;
2994 case RACE_TROLL:
2995 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
2996 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_TROLL));
2997 break;
2998#if VERSION_STRING > Classic
2999 case RACE_BLOODELF:
3000 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
3001 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_THALASSIAN));
3002 break;
3003#endif
3004#if VERSION_STRING >= Cata
3005 case RACE_WORGEN:
3006 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
3007 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_GILNEAN));
3008 break;
3009 case RACE_GOBLIN:
3010 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
3011 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_GOBLIN));
3012 break;
3013#endif
3014#if VERSION_STRING >= Mop
3016 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
3017 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
3018 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_PANDAREN_NEUTRAL));
3019 break;
3021 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_COMMON));
3022 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_PANDAREN_ALLIANCE));
3023 break;
3025 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_ORCISH));
3026 CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", static_cast<uint32_t>(guid), getSpellIdForLanguage(SKILL_LANG_PANDAREN_HORDE));
3027 break;
3028#endif
3029 }
3030}
3031
3033{
3034 sLogger.debug("Player {} gets prepared for login.", getName());
3035
3036#if VERSION_STRING == Mop
3038
3039 smsg_TalentsInfo(false);
3040
3041 WorldPacket data(SMSG_WORLD_SERVER_INFO, 4 + 4 + 1 + 1);
3042 data.writeBit(0);
3043 data.writeBit(0);
3044 data.writeBit(0);
3045 data.writeBit(0);
3046 data.flushBits();
3047
3048 data << uint8_t(0);
3049 data << uint32_t(0); // reset weekly quest time
3050 data << uint32_t(0);
3051 getSession()->SendPacket(&data);
3052
3054
3055 m_session->SendPacket(SmsgSendUnlearnSpells().serialise().get());
3056
3057 sendActionBars(0);
3058
3060
3062 data.writeBits(0, 19);
3063 getSession()->SendPacket(&data);
3064
3065 m_session->SendPacket(SmsgLoginSetTimeSpeed(Util::getGameTime(), 0.0166666669777748f).serialise().get());
3066
3067 data.Initialize(SMSG_SET_FORCED_REACTIONS, 1 + 4 + 4);
3068 data.writeBits(0, 6);
3069 data.flushBits();
3070 getSession()->SendPacket(&data);
3071
3072 data.Initialize(SMSG_SETUP_CURRENCY, 3 + 1 + 4 + 4 + 4 + 4);
3073 data.writeBits(0, 21);
3074 getSession()->SendPacket(&data);
3075
3076 ObjectGuid guid = getGuid();
3078 data.writeBit(guid[5]);
3079 data.writeBit(guid[1]);
3080 data.writeBit(guid[4]);
3081 data.writeBit(guid[2]);
3082 data.writeBit(guid[3]);
3083 data.writeBit(guid[7]);
3084 data.writeBit(guid[0]);
3085 data.writeBit(guid[6]);
3086
3087 data.WriteByteSeq(guid[4]);
3088 data.WriteByteSeq(guid[6]);
3089 data.WriteByteSeq(guid[2]);
3090 data.WriteByteSeq(guid[0]);
3091 data.WriteByteSeq(guid[3]);
3092 data.WriteByteSeq(guid[7]);
3093 data.WriteByteSeq(guid[5]);
3094 data.WriteByteSeq(guid[1]);
3095 getSession()->SendPacket(&data);
3096
3097#else
3099
3100 std::vector<uint32_t> tutorials;
3101 for (auto tutorial : m_tutorials)
3102 tutorials.push_back(tutorial);
3103
3104 m_session->SendPacket(SmsgTutorialFlags(tutorials).serialise().get());
3105
3106#if VERSION_STRING > TBC
3107 smsg_TalentsInfo(false);
3108#endif
3109
3111
3112 m_session->SendPacket(SmsgSendUnlearnSpells().serialise().get());
3113
3114 sendActionBars(0);
3116
3117 m_session->SendPacket(SmsgLoginSetTimeSpeed(Util::getGameTime(), 0.0166666669777748f).serialise().get());
3118
3119 updateSpeed();
3120
3121#if VERSION_STRING > TBC
3122 m_session->SendPacket(SmsgUpdateWorldState(0xC77, worldConfig.arena.arenaProgress, 0xF3D, worldConfig.arena.arenaSeason).serialise().get());
3123#endif
3124#endif
3125
3126 sLogger.info("WORLD: Sent initial logon packets for {}.", getName());
3127}
3128
3129//////////////////////////////////////////////////////////////////////////////////////////
3130// Session & Packets
3132void Player::setSession(WorldSession* session) { m_session = session; }
3133
3135{
3136 if (m_session)
3137 {
3139 sendPacket(SmsgCharacterLoginFailed(respons).serialise().get());
3140 m_session->m_loggingInPlayer = nullptr;
3141 }
3142
3143 m_isReadyToBeRemoved = true;
3144 delete this;
3145}
3146
3148{
3149 sEventMgr.RemoveEvents(this, EVENT_PLAYER_SOFT_DISCONNECT);
3150
3151 if (m_session)
3152 m_session->LogoutPlayer(true);
3153}
3154
3155void Player::outPacket(uint16_t opcode, uint16_t length, const void* data)
3156{
3157 if (m_session)
3158 m_session->OutPacket(opcode, length, data);
3159}
3160
3162{
3163 if (m_session)
3164 m_session->SendPacket(packet);
3165}
3166
3167void Player::outPacketToSet(uint16_t opcode, uint16_t length, const void* data, bool sendToSelf)
3168{
3169 if (!IsInWorld())
3170 return;
3171
3172 if (sendToSelf)
3173 outPacket(opcode, length, data);
3174
3175 for (const auto& objectPlayer : getInRangePlayersSet())
3176 {
3177 if (Player* player = static_cast<Player*>(objectPlayer))
3178 {
3179 if (m_isGmInvisible)
3180 {
3181 if (player->getSession()->hasPermissions())
3182 player->outPacket(opcode, length, data);
3183 }
3184 else
3185 {
3186 player->outPacket(opcode, length, data);
3187 }
3188 }
3189 }
3190}
3191
3192void Player::sendMessageToSet(WorldPacket* data, bool sendToSelf, bool sendToOwnTeam)
3193{
3194 if (!IsInWorld())
3195 return;
3196
3197 if (sendToSelf)
3198 sendPacket(data);
3199
3200 for (const auto& objectPlayer : getInRangePlayersSet())
3201 {
3202 if (Player* player = static_cast<Player*>(objectPlayer))
3203 {
3204 if (player->getSession() == nullptr)
3205 continue;
3206
3207 if (sendToOwnTeam && player->getTeam() != getTeam())
3208 continue;
3209
3210 if ((player->GetPhase() & GetPhase()) == 0)
3211 continue;
3212
3213 if (data->GetOpcode() != SMSG_MESSAGECHAT)
3214 {
3215 if (m_isGmInvisible && !player->getSession()->hasPermissions())
3216 continue;
3217
3218 if (player->isVisibleObject(getGuid()))
3219 player->sendPacket(data);
3220 }
3221 else
3222 {
3223 if (!player->isIgnored(getGuidLow()))
3224 player->sendPacket(data);
3225 }
3226 }
3227 }
3228}
3229
3230void Player::sendDelayedPacket(WorldPacket* data, bool deleteDataOnSend)
3231{
3232 if (data == nullptr)
3233 return;
3234
3235 if (m_session)
3236 m_session->SendPacket(data);
3237
3238 if (deleteDataOnSend)
3239 delete data;
3240}
3241
3243{
3244 uint32_t destsize = size + size / 10 + 16;
3245 int rate = worldConfig.getIntRate(INTRATE_COMPRESSION);
3246 if (size >= 40000 && rate < 6)
3247 rate = 6;
3248
3249 // set up stream
3250 z_stream stream;
3251 stream.zalloc = nullptr;
3252 stream.zfree = nullptr;
3253 stream.opaque = nullptr;
3254
3255 if (deflateInit(&stream, rate) != Z_OK)
3256 {
3257 sLogger.failure("deflateInit failed.");
3258 return false;
3259 }
3260
3261 auto buffer = std::make_unique<uint8_t[]>(destsize);
3262
3263 // set up stream pointers
3264 stream.next_out = (Bytef*)buffer.get() + 4;
3265 stream.avail_out = destsize;
3266 stream.next_in = (Bytef*)update_buffer;
3267 stream.avail_in = size;
3268
3269 // call the actual process
3270 if (deflate(&stream, Z_NO_FLUSH) != Z_OK ||
3271 stream.avail_in != 0)
3272 {
3273 sLogger.failure("deflate failed.");
3274 return false;
3275 }
3276
3277 // finish the deflate
3278 if (deflate(&stream, Z_FINISH) != Z_STREAM_END)
3279 {
3280 sLogger.failure("deflate failed: did not end stream");
3281 return false;
3282 }
3283
3284 // finish up
3285 if (deflateEnd(&stream) != Z_OK)
3286 {
3287 sLogger.failure("deflateEnd failed.");
3288 return false;
3289 }
3290
3291 // fill in the full size of the compressed stream
3292 *(uint32_t*)&buffer[0] = size;
3293
3294#if VERSION_STRING < Cata
3295 m_session->OutPacket(SMSG_COMPRESSED_UPDATE_OBJECT, static_cast<uint16_t>(stream.total_out) + 4, buffer.get());
3296#else
3297 m_session->OutPacket(SMSG_UPDATE_OBJECT, static_cast<uint16_t>(stream.total_out) + 4, buffer.get());
3298#endif
3299
3300 return true;
3301}
3302
3304{
3305 uint32_t count = 0;
3306 if (target == this)
3307 count += getItemInterface()->m_CreateForPlayer(data);
3308
3309 count += Unit::buildCreateUpdateBlockForPlayer(data, target);
3310
3311 return count;
3312}
3313
3315
3317{
3318#if VERSION_STRING == Mop
3320
3329
3332
3335
3338
3341
3344
3351
3358
3362
3368
3385
3394
3400
3401 for (uint16_t i = 0; i < EQUIPMENT_SLOT_END; ++i)
3402 {
3403 uint32_t offset = i * 2;
3404
3407 }
3408
3409 uint16_t questIdOffset = 5;
3410 for (uint16_t i = getOffsetForStructuredField(WoWPlayer, quests); i < getOffsetForStructuredField(WoWPlayer, visible_items); i += questIdOffset)
3412
3414
3415#else
3419#if VERSION_STRING < Cata
3421#else
3423#endif
3424
3427
3430
3433
3440#if VERSION_STRING == WotLK
3443#endif
3444
3451#if VERSION_STRING == WotLK
3454#endif
3455
3459
3460#if VERSION_STRING <= TBC
3467#endif
3468
3473#if VERSION_STRING != Classic
3475#endif
3476
3492#if VERSION_STRING > TBC
3494#endif
3495
3504#if VERSION_STRING < Cata
3506#endif
3511
3512#if VERSION_STRING == TBC
3519#endif
3520
3521 for (uint16_t i = 0; i < EQUIPMENT_SLOT_END; ++i)
3522 {
3523#if VERSION_STRING > TBC
3524 uint32_t offset = i * 2;
3525#else
3526 uint32_t offset = i * 16;
3527#endif
3528 // visible_items includes creator guid, so add + 2 since we are not sending that as update field
3531 }
3532
3533#if VERSION_STRING == Classic
3534 uint16_t questIdOffset = 3;
3535#elif VERSION_STRING == TBC
3536 uint16_t questIdOffset = 4;
3537#else
3538 uint16_t questIdOffset = 5;
3539#endif
3540
3541 for (uint16_t i = getOffsetForStructuredField(WoWPlayer, quests); i < getOffsetForStructuredField(WoWPlayer, visible_items); i += questIdOffset)
3543
3544#if VERSION_STRING != Classic
3546#endif
3547#endif
3548}
3549
3550void Player::copyAndSendDelayedPacket(WorldPacket* data) { m_updateMgr.queueDelayedPacket(std::make_unique<WorldPacket>(*data)); }
3551
3553
3555
3556void Player::setCreateBits(UpdateMask* updateMask, Player* target) const
3557{
3558 if (target == this)
3559 {
3560 Object::setCreateBits(updateMask, target);
3561 }
3562 else
3563 {
3564 for (uint32_t index = 0; index < m_valuesCount; index++)
3565 {
3566 if (m_uint32Values[index] != 0 && Player::m_visibleUpdateMask.GetBit(index))
3567 updateMask->SetBit(index);
3568 }
3569 }
3570}
3571
3572void Player::setUpdateBits(UpdateMask* updateMask, Player* target) const
3573{
3574 if (target == this)
3575 {
3576 Object::setUpdateBits(updateMask, target);
3577 }
3578 else
3579 {
3580 Object::setUpdateBits(updateMask, target);
3581 *updateMask &= Player::m_visibleUpdateMask;
3582 }
3583}
3584
3585//////////////////////////////////////////////////////////////////////////////////////////
3586// Visiblility
3589{
3590 if (isVisibleObject(guid))
3591 {
3592 m_visibleObjects.erase(guid);
3593#if VERSION_STRING <= TBC
3594 if (WoWGuid(guid).isGameObject() && !WoWGuid(guid).isTransport() && !WoWGuid(guid).isTransporter())
3596#endif
3597 }
3598}
3599bool Player::isVisibleObject(uint64_t guid) { return m_visibleObjects.contains(guid); }
3600
3602{
3603 if (m_visibleObjects.contains(guid))
3604 {
3605 m_visibleObjects.erase(guid);
3606#if VERSION_STRING <= TBC
3607 if (WoWGuid(guid).isGameObject() && !WoWGuid(guid).isTransport() && !WoWGuid(guid).isTransporter())
3609#endif
3611 }
3612}
3613
3614//////////////////////////////////////////////////////////////////////////////////////////
3615// Stats
3617{
3618 if (m_levelInfo != nullptr)
3619 {
3622 }
3623 else
3624 {
3625 sLogger.failure("Major error in Player::setInitialPlayerData : No LevelInfo for player (level {}, race {}, class {})!", getLevel(), getRace(), getClass());
3626
3627 setBaseHealth(1);
3628 setBaseMana(1);
3629 }
3630
3631 // Set max health and powers
3633
3634 // First initialize all power fields to 0
3635 for (uint8_t power = POWER_TYPE_MANA; power < TOTAL_PLAYER_POWER_TYPES; ++power)
3636 setMaxPower(static_cast<PowerType>(power), 0);
3637
3638 // Next set correct power for each class
3639 switch (getClass())
3640 {
3641 case WARRIOR:
3642 {
3644 } break;
3645#if VERSION_STRING >= Cata
3646 case HUNTER:
3647 {
3649 } break;
3650#endif
3651 case ROGUE:
3652 {
3654 } break;
3655#if VERSION_STRING >= WotLK
3656 case DEATHKNIGHT:
3657 {
3660 } break;
3661#endif
3662 default:
3663 {
3664#if VERSION_STRING >= Cata
3665 // Another switch case to set secondary powers
3666 switch (getClass())
3667 {
3668 case PALADIN:
3670 break;
3671 case WARLOCK:
3673 break;
3674 case DRUID:
3676 break;
3677 default:
3678 break;
3679 }
3680#endif
3682 } break;
3683 }
3684
3685 setMinDamage(0.0f);
3686 setMaxDamage(0.0f);
3687 setMinOffhandDamage(0.0f);
3688 setMaxOffhandDamage(0.0f);
3689 setMinRangedDamage(0.0f);
3690 setMaxRangedDamage(0.0f);
3691
3692 setBaseAttackTime(MELEE, 2000);
3695
3696 setAttackPower(0);
3702
3703 setBlockPercentage(0.0f);
3704 setDodgePercentage(0.0f);
3705 setParryPercentage(0.0f);
3708#if VERSION_STRING >= TBC
3709 setExpertise(0);
3712 setShieldBlock(0);
3713#endif
3714#if VERSION_STRING >= WotLK
3716#endif
3717
3718#if VERSION_STRING >= TBC
3720
3723#endif
3724
3725 setModCastSpeed(1.0f);
3726
3727 for (uint8_t i = 0; i < TOTAL_SPELL_SCHOOLS; ++i)
3728 {
3731 setModDamageDonePct(1.0f, i);
3732
3733#if VERSION_STRING >= TBC
3734 setSpellCritPercentage(i, 0.0f);
3735#endif
3736 setResistance(i, 0);
3737
3739 setPowerCostMultiplier(i, 0.0f);
3740 }
3741
3742#if VERSION_STRING >= WotLK
3743 for (uint8_t i = 0; i < WOWPLAYER_NO_REAGENT_COST_COUNT; ++i)
3744 {
3745 setNoReagentCost(i, 0);
3746 }
3747#endif
3748
3749 for (uint8_t i = 0; i < MAX_PCR; ++i)
3750 setCombatRating(i, 0);
3751
3752 for (uint8_t i = 0; i < STAT_COUNT; ++i)
3753 {
3754 m_baseStats[i] = m_levelInfo->Stat[i];
3755 calcStat(i);
3756 }
3757
3758 updateStats();
3759
3760 setMaxLevel(worldConfig.player.playerLevelCap);
3761
3763#if VERSION_STRING == TBC
3765#elif VERSION_STRING >= WotLK
3766 addUnitFlags2(UNIT_FLAG2_ENABLE_POWER_REGEN);
3767#endif
3768
3769 // Set current health and power after stats are loaded
3775#if VERSION_STRING >= WotLK
3778#endif
3779}
3780
3782{
3783#if VERSION_STRING < WotLK
3784 // Rage
3785 m_rageRegenerateTimer += diff;
3786 if (m_rageRegenerateTimer >= REGENERATION_INTERVAL_RAGE)
3787 {
3788 regeneratePower(POWER_TYPE_RAGE, m_rageRegenerateTimer);
3789 m_rageRegenerateTimer = 0;
3790 }
3791#endif
3792
3793#if VERSION_STRING >= Cata
3794 // Holy Power
3795 if (isClassPaladin())
3796 {
3799 {
3802 }
3803 }
3804#endif
3805
3806 // Food/Drink visual effect
3807 // Confirmed from sniffs that the timer keeps going on even when there is no food/drink aura
3808 if (diff >= m_foodDrinkSpellVisualTimer)
3809 {
3810 // Find food/drink aura
3811 const auto findFoodOrDrinkAura = [this](AuraEffect auraEffect) -> bool
3812 {
3813 for (const auto& aurEff : getAuraEffectList(auraEffect))
3814 {
3815 if (aurEff->getAura()->IsPassive() || aurEff->getAura()->isNegative())
3816 continue;
3817 if (aurEff->getAura()->getSpellInfo()->getAuraInterruptFlags() & AURA_INTERRUPT_ON_STAND_UP)
3818 return true;
3819 }
3820 return false;
3821 };
3822
3823 // Food takes priority over drink
3824 if (findFoodOrDrinkAura(SPELL_AURA_MOD_HEALTH_REGEN) || findFoodOrDrinkAura(SPELL_AURA_PERIODIC_HEAL_PCT))
3826 else if (findFoodOrDrinkAura(SPELL_AURA_MOD_POWER_REGEN) || findFoodOrDrinkAura(SPELL_AURA_PERIODIC_POWER_PCT))
3828
3830 }
3831 else
3832 {
3834 }
3835}
3836
3837#if VERSION_STRING >= Cata
3842#endif
3843
3844//////////////////////////////////////////////////////////////////////////////////////////
3845// Database stuff
3847{
3848 // Add initial spells on first login
3849 if (m_firstLogin)
3850 {
3851 for (const auto& spellId : m_playerCreateInfo->spell_list)
3852 addSpell(spellId);
3853
3854 return true;
3855 }
3856
3857 if (result == nullptr)
3858 return false;
3859
3860 do
3861 {
3862 const auto fields = result->Fetch();
3863 const auto spellId = fields[0].asUint32();
3864
3865 // addSpell will validate spell id
3866 addSpell(spellId);
3867 } while (result->NextRow());
3868
3869 return true;
3870}
3871
3873{
3874 if (result == nullptr)
3875 return false;
3876
3877 do
3878 {
3879 const auto fields = result->Fetch();
3880
3881 const auto skillid = fields[0].asUint16();
3882 const auto currval = fields[1].asUint16();
3883 const auto maxval = fields[2].asUint16();
3884
3885 addSkillLine(skillid, currval, maxval);
3886 } while (result->NextRow());
3887
3888 return true;
3889}
3890
3892{
3893 // Add initial reputations on first login
3894 if (m_firstLogin)
3895 {
3897 return true;
3898 }
3899
3900 if (result == nullptr)
3901 return false;
3902
3903 do
3904 {
3905 const auto field = result->Fetch();
3906
3907 const auto id = field[0].asUint32();
3908 const auto flag = field[1].asUint8();
3909 const auto basestanding = field[2].asInt32();
3910 const auto standing = field[3].asInt32();
3911
3912 const auto faction = sFactionStore.lookupEntry(id);
3913 if (faction == nullptr || faction->RepListId < 0)
3914 continue;
3915
3916 const auto [repItr, _] = m_reputation.insert_or_assign(id, std::make_unique<FactionReputation>(standing, flag, basestanding));
3917 m_reputationByListId[faction->RepListId] = repItr->second.get();
3918 } while (result->NextRow());
3919
3920 return true;
3921}
3922
3923//////////////////////////////////////////////////////////////////////////////////////////
3924// Spells and skills
3925bool Player::hasSpell(uint32_t spellId) const
3926{
3927 return m_spellSet.find(spellId) != m_spellSet.cend();
3928}
3929
3931{
3932 return m_deletedSpellSet.find(spellId) != m_deletedSpellSet.cend();
3933}
3934
3935void Player::addSpell(uint32_t spellId, uint16_t fromSkill/* = 0*/)
3936{
3937 _addSpell(spellId, fromSkill, false, false);
3938}
3939
3941{
3942 m_deletedSpellSet.emplace(spellId);
3943}
3944
3945bool Player::removeSpell(uint32_t spellId, bool moveToDeleted)
3946{
3947 return _removeSpell(spellId, moveToDeleted, false, false, false);
3948}
3949
3951{
3952 const auto itr = std::as_const(m_deletedSpellSet).find(spellId);
3953 if (itr == m_deletedSpellSet.cend())
3954 return false;
3955
3956 m_deletedSpellSet.erase(itr);
3957 return true;
3958}
3959
3961{
3962 return m_spellSet;
3963}
3964
3966{
3967 return m_deletedSpellSet;
3968}
3969
3971{
3972 auto smsgInitialSpells = SmsgSendKnownSpells();
3973
3974 uint32_t mstime = Util::getMSTime();
3975
3976 for (const auto& spellId : m_spellSet)
3977 {
3978 smsgInitialSpells.addSpellIds(spellId);
3979 }
3980
3981 for (auto itr = m_cooldownMap[COOLDOWN_TYPE_SPELL].begin(); itr != m_cooldownMap[COOLDOWN_TYPE_SPELL].end();)
3982 {
3983 auto itr2 = itr++;
3984
3985 if (itr2->second.ExpireTime < mstime || (itr2->second.ExpireTime - mstime) < 10000)
3986 {
3988 continue;
3989 }
3990
3991 sLogger.debug("InitialSpells sending spell cooldown for spell {} to {} ms", itr2->first, itr2->second.ExpireTime - mstime);
3992
3993 smsgInitialSpells.addSpellCooldown(itr2->first, itr2->second.ItemId, 0, itr2->second.ExpireTime - mstime, 0);
3994 }
3995
3996 for (auto itr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].begin(); itr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end();)
3997 {
3998 PlayerCooldownMap::iterator itr2 = itr++;
3999
4000 if (itr2->second.ExpireTime < mstime || (itr2->second.ExpireTime - mstime) < 10000)
4001 {
4003 continue;
4004 }
4005
4006 sLogger.debug("InitialSpells sending category cooldown for cat {} to {} ms", itr2->first, itr2->second.ExpireTime - mstime);
4007
4008 smsgInitialSpells.addSpellCooldown(itr2->first, itr2->second.ItemId, static_cast<uint16_t>(itr2->first), 0, itr2->second.ExpireTime - mstime);
4009 }
4010
4011 getSession()->SendPacket(smsgInitialSpells.serialise().get());
4012}
4013
4015{
4016 std::vector<SmsgSpellCooldownMap> spellCoodlownMap;
4017
4018 for (const auto& SpellId : m_spellSet)
4019 {
4020 if (const auto* spellInfo = sSpellMgr.getSpellInfo(SpellId))
4021 {
4022 // Not send cooldown for this spells
4023 if (spellInfo->getAttributes() & ATTRIBUTES_TRIGGER_COOLDOWN)
4024 continue;
4025
4026 if (spellInfo->getFirstSchoolFromSchoolMask() == spellSchool)
4027 {
4028 SmsgSpellCooldownMap smsgSpellCooldownMap;
4029 smsgSpellCooldownMap.spellId = SpellId;
4030 smsgSpellCooldownMap.duration = timeMs;
4031
4032 spellCoodlownMap.push_back(smsgSpellCooldownMap);
4033 }
4034 }
4035 }
4036 getSession()->SendPacket(SmsgSpellCooldown(getGuid(), 0x0, spellCoodlownMap).serialise().get());
4037}
4038
4040{
4041 if (PlayerCreateInfo const* playerCreateInfo = sMySQLStore.getPlayerCreateInfo(getRace(), getClass()))
4042 {
4043 std::list<uint32_t> spelllist;
4044
4045 for (const auto& spellId : m_spellSet)
4046 spelllist.push_back(spellId);
4047
4048 for (std::list<uint32_t>::iterator itr = spelllist.begin(); itr != spelllist.end(); ++itr)
4049 removeSpell((*itr), false);
4050
4051 m_deletedSpellSet.clear();
4052
4053 for (std::set<uint32_t>::iterator sp = playerCreateInfo->spell_list.begin(); sp != playerCreateInfo->spell_list.end(); ++sp)
4054 {
4055 if (*sp)
4056 addSpell(*sp);
4057 }
4058 }
4059}
4060
4062{
4063 SpellInfo const* spellInfo = sSpellMgr.getSpellInfo(spellId);
4064 m_shapeshiftSpells.emplace(spellId);
4065
4066 if (spellInfo->getRequiredShapeShift() && getShapeShiftMask() & spellInfo->getRequiredShapeShift())
4067 {
4068 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
4069 SpellCastTargets spellCastTargets(this->getGuid());
4070 spell->prepare(&spellCastTargets);
4071 }
4072}
4073
4075{
4076 m_shapeshiftSpells.erase(spellId);
4077 removeAllAurasById(spellId);
4078}
4079
4081{
4082 return m_shapeshiftSpells;
4083}
4084
4085void Player::sendAvailSpells(WDB::Structures::SpellShapeshiftFormEntry const* shapeshiftFormEntry, bool active)
4086{
4087 if (active)
4088 {
4089 if (!shapeshiftFormEntry)
4090 return;
4091
4092 // Send the spells
4093 SmsgPetActionsArray actions{};
4094 for (uint8_t i = 0; i < 8; ++i)
4095 {
4096#if VERSION_STRING >= TBC
4097 actions[i] = packPetActionButtonData(shapeshiftFormEntry->spells[i], PET_SPELL_STATE_DEFAULT);
4098#else
4099 actions[i] = 0;
4100#endif
4101 }
4102 actions[8] = 0;
4103 actions[9] = 0;
4104
4105 getSession()->SendPacket(SmsgPetSpells(getGuid(), 0, 0, 0, 0, 0, std::move(actions), SmsgPetSpellsVector()).serialise().get());
4106 }
4107 else
4108 {
4110 }
4111}
4112
4114{
4115 //\todo shapeshiftform is never negative.
4116 int s = getShapeShiftForm();
4117 if (s <= 0)
4118 return false;
4119
4120 // Fight forms that do not use player's weapon
4121 return (s == FORM_BEAR || s == FORM_DIREBEAR || s == FORM_CAT); //Shady: actually ghostwolf form doesn't use weapon too.
4122}
4123
4124#if VERSION_STRING >= TBC
4126{
4128 {
4129 WDB::Structures::SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.lookupEntry(form);
4130 if (!shapeshift)
4131 return true;
4132
4133 if (!(shapeshift->Flags & 0x1))
4134 return true;
4135 }
4136
4138 return false;
4139
4141 if (!display)
4142 return true;
4143
4145 if (!displayExtra)
4146 return true;
4147
4148 WDB::Structures::CreatureModelDataEntry const* model = sCreatureModelDataStore.lookupEntry(display->ModelID);
4149 WDB::Structures::ChrRacesEntry const* race = sChrRacesStore.lookupEntry(displayExtra->Race);
4150
4151 if (model && !(model->Flags & 0x80))
4152 if (race && !(race->flags & 0x4))
4153 return true;
4154
4155 return false;
4156}
4157#else
4159{
4161 return form != FORM_NORMAL && form != FORM_BATTLESTANCE && form != FORM_BERSERKERSTANCE && form != FORM_DEFENSIVESTANCE &&
4162 form != FORM_SHADOW && form != FORM_STEALTH;
4163}
4164#endif
4165
4167{
4168 // Get the autorepeat spell
4169 const auto autoRepeatSpell = getCurrentSpell(CURRENT_AUTOREPEAT_SPELL);
4170
4171 // If player is moving or casting a spell, interrupt wand casting and delay auto shot
4172 const auto isAutoShot = autoRepeatSpell->getSpellInfo()->getId() == 75;
4173 if (m_isMoving || isCastingSpell(false, true, isAutoShot))
4174 {
4175 if (!isAutoShot)
4176 {
4178 }
4179 m_FirstCastAutoRepeat = true;
4180 return;
4181 }
4182
4183 // Apply delay to wand shooting
4184 if (m_FirstCastAutoRepeat && (getAttackTimer(RANGED) - Util::getMSTime() < 500) && !isAutoShot)
4185 {
4186 setAttackTimer(RANGED, 500);
4187 }
4188 m_FirstCastAutoRepeat = false;
4189
4190 if (isAttackReady(RANGED))
4191 {
4192 const auto canCastAutoRepeatSpell = autoRepeatSpell->canCast(true, 0, 0);
4193 if (canCastAutoRepeatSpell != SPELL_CAST_SUCCESS)
4194 {
4195 if (!isAutoShot)
4197 else if (isPlayer())
4198 autoRepeatSpell->sendCastResult(canCastAutoRepeatSpell);
4199 return;
4200 }
4201
4202 // Cast the spell with triggered flag
4203 const auto newAutoRepeatSpell = sSpellMgr.newSpell(this, autoRepeatSpell->getSpellInfo(), true, nullptr);
4204 newAutoRepeatSpell->prepare(&autoRepeatSpell->m_targets);
4205
4207 }
4208}
4209
4211{
4212#if VERSION_STRING == Classic
4213 return false;
4214#else
4215 auto areaEntry = GetArea();
4216 if (areaEntry == nullptr)
4217 // If area is null, try finding any area from the zone with zone id
4219 if (areaEntry == nullptr)
4220 return false;
4221
4222 // Not flyable areas (such as Dalaran in wotlk)
4224 return false;
4225
4226 // Get continent map id
4227 auto mapId = GetMapId();
4228 if (mapId == 530 || mapId == 571)
4229 {
4230 const auto worldMapEntry = sWorldMapAreaStore.lookupEntry(getZoneId());
4231 if (worldMapEntry != nullptr)
4232 mapId = worldMapEntry->continentMapId >= 0 ? worldMapEntry->continentMapId : worldMapEntry->mapId;
4233 }
4234
4235 switch (mapId)
4236 {
4237 // Eastern Kingdoms
4238 case 0:
4239 // Kalimdor
4240 case 1:
4241 // Flight Master's License
4242 if (!hasSpell(90267))
4243 return false;
4244 break;
4245 // Outland
4246 case 530:
4247 return true;
4248 // Northrend
4249 case 571:
4250 // Cold Weather Flying
4251 if (!hasSpell(54197))
4252 return false;
4253 break;
4254 default:
4255 return false;
4256 }
4257 return true;
4258#endif
4259}
4260
4262{
4263 return m_canDualWield2H;
4264}
4265
4266void Player::setDualWield2H(bool enable)
4267{
4268 m_canDualWield2H = enable;
4269}
4270
4272{
4273 const auto spellSkillRange = sSpellMgr.getSkillEntryRangeForSpell(spell_id);
4274
4275 // If spell does not exist in sSkillLineAbilityStore assume it fits for player
4276 if (spellSkillRange.empty())
4277 return true;
4278
4279 const auto raceMask = getRaceMask();
4280 const auto classMask = getClassMask();
4281
4282 for (const auto& [_, skillEntry] : spellSkillRange)
4283 {
4284 // skip wrong race skills
4285 if (skillEntry->race_mask > 0 && !(skillEntry->race_mask & raceMask))
4286 continue;
4287
4288 // skip wrong class skills
4289 if (skillEntry->class_mask > 0 && !(skillEntry->class_mask & classMask))
4290 continue;
4291
4292 return true;
4293 }
4294
4295 return false;
4296}
4297
4299{
4300 const auto curTime = Util::getMSTime();
4301
4302 // Check category cooldown
4303 if (spellInfo->getCategory() > 0)
4304 {
4305 const auto itr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].find(spellInfo->getCategory());
4306 if (itr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end())
4307 {
4308 if (curTime < itr->second.ExpireTime)
4309 return true;
4310
4311 // Cooldown has expired
4313 }
4314 }
4315
4316 // Check spell cooldown
4317 const auto itr = m_cooldownMap[COOLDOWN_TYPE_SPELL].find(spellInfo->getId());
4318 if (itr != m_cooldownMap[COOLDOWN_TYPE_SPELL].end())
4319 {
4320 if (curTime < itr->second.ExpireTime)
4321 return true;
4322
4323 // Cooldown has expired
4325 }
4326
4327 return false;
4328}
4329
4331{
4332 const auto curTime = Util::getMSTime();
4333
4334 // Check for cooldown cheat as well
4335 if (spellInfo->getStartRecoveryTime() > 0 && m_globalCooldown > 0 && !m_cheats.hasCooldownCheat)
4336 {
4337 if (curTime < m_globalCooldown)
4338 return true;
4339
4340 // Global cooldown has expired
4341 m_globalCooldown = 0;
4342 }
4343
4344 return false;
4345}
4346
4347void Player::addSpellCooldown(SpellInfo const* spellInfo, Item const* itemCaster, Spell* castingSpell/* = nullptr*/, int32_t cooldownTime/* = 0*/)
4348{
4349 const auto curTime = Util::getMSTime();
4350 const auto spellId = spellInfo->getId();
4351
4352 // Set category cooldown
4353 int32_t spellCategoryCooldown = static_cast<int32_t>(spellInfo->getCategoryRecoveryTime());
4354 if (spellCategoryCooldown > 0 && spellInfo->getCategory() > 0)
4355 {
4356 // Add cooldown modifiers
4357 if (castingSpell != nullptr)
4358 applySpellModifiers(SPELLMOD_COOLDOWN_DECREASE, &spellCategoryCooldown, spellInfo, castingSpell);
4359
4360 _addCategoryCooldown(spellInfo->getCategory(), spellCategoryCooldown + curTime, spellId, itemCaster != nullptr ? itemCaster->getEntry() : 0);
4361 }
4362
4363 // Set spell cooldown
4364 int32_t spellCooldown = cooldownTime == 0 ? static_cast<int32_t>(spellInfo->getRecoveryTime()) : cooldownTime;
4365 if (spellCooldown > 0)
4366 {
4367 // Add cooldown modifers
4368 if (castingSpell != nullptr)
4369 applySpellModifiers(SPELLMOD_COOLDOWN_DECREASE, &spellCooldown, spellInfo, castingSpell);
4370
4371 _addCooldown(COOLDOWN_TYPE_SPELL, spellId, spellCooldown + curTime, spellId, itemCaster != nullptr ? itemCaster->getEntry() : 0);
4372 }
4373
4374 // Send cooldown packet
4375 sendSpellCooldownPacket(spellInfo, spellCooldown > spellCategoryCooldown ? spellCooldown : spellCategoryCooldown, false);
4376}
4377
4378void Player::addGlobalCooldown(SpellInfo const* spellInfo, Spell* castingSpell, const bool sendPacket/* = false*/)
4379{
4380 if (spellInfo->getStartRecoveryTime() == 0 && spellInfo->getStartRecoveryCategory() == 0)
4381 return;
4382
4383 const auto curTime = Util::getMSTime();
4384 auto gcdDuration = static_cast<int32_t>(spellInfo->getStartRecoveryTime());
4385
4386 // Apply global cooldown modifiers
4387 applySpellModifiers(SPELLMOD_GLOBAL_COOLDOWN, &gcdDuration, spellInfo, castingSpell);
4388
4389 // Apply haste modifier only to magic spells
4390 if (spellInfo->getStartRecoveryCategory() == 133 && spellInfo->getDmgClass() == SPELL_DMG_TYPE_MAGIC &&
4391 !(spellInfo->getAttributes() & ATTRIBUTES_RANGED) && !(spellInfo->getAttributes() & ATTRIBUTES_ABILITY))
4392 {
4393 gcdDuration = static_cast<int32_t>(gcdDuration * getModCastSpeed());
4394
4395 // Global cooldown cannot be shorter than 1 second or longer than 1.5 seconds
4396 gcdDuration = std::max(gcdDuration, 1000);
4397 gcdDuration = std::min(gcdDuration, 1500);
4398 }
4399
4400 if (gcdDuration <= 0)
4401 return;
4402
4403 m_globalCooldown = curTime + gcdDuration;
4404
4405 if (sendPacket)
4406 sendSpellCooldownPacket(spellInfo, 0, true);
4407}
4408
4409void Player::sendSpellCooldownPacket(SpellInfo const* spellInfo, const uint32_t duration, const bool isGcd)
4410{
4411 std::vector<SmsgSpellCooldownMap> spellMap;
4412
4413 SmsgSpellCooldownMap mapMembers;
4414 mapMembers.spellId = spellInfo->getId();
4415 mapMembers.duration = duration;
4416
4417 spellMap.push_back(mapMembers);
4418
4419 sendMessageToSet(SmsgSpellCooldown(GetNewGUID(), isGcd, spellMap).serialise().get(), true);
4420}
4421
4423{
4424 const auto spellInfo = sSpellMgr.getSpellInfo(spellId);
4425 if (spellInfo == nullptr)
4426 return;
4427
4428 // Send cooldown clear packet
4429 getSession()->SendPacket(SmsgClearCooldown(spellId, getGuid()).serialise().get());
4430
4431 for (uint8_t i = 0; i < NUM_COOLDOWN_TYPES; ++i)
4432 {
4433 for (auto itr = m_cooldownMap[i].begin(); itr != m_cooldownMap[i].end();)
4434 {
4435 auto cooldown = (*itr);
4436 if ((i == COOLDOWN_TYPE_CATEGORY && cooldown.first == spellInfo->getCategory()) ||
4437 (i == COOLDOWN_TYPE_SPELL && cooldown.first == spellInfo->getId()))
4438 {
4439 itr = m_cooldownMap[i].erase(itr);
4440 }
4441 else
4442 {
4443 ++itr;
4444 }
4445 }
4446 }
4447}
4448
4453
4455{
4456 // Clear spell cooldowns
4457 for (const auto& spell : m_spellSet)
4458 clearCooldownForSpell(spell);
4459
4460 // Clear global cooldown
4462
4463 // Clear other cooldowns, like items
4464 for (uint8_t i = 0; i < NUM_COOLDOWN_TYPES; ++i)
4465 {
4466 for (auto itr = m_cooldownMap[i].begin(); itr != m_cooldownMap[i].end();)
4467 {
4468 auto spellId = (*itr).second.SpellId;
4469 getSession()->SendPacket(SmsgClearCooldown(spellId, getGuid()).serialise().get());
4470 itr = m_cooldownMap[i].erase(itr);
4471 }
4472 }
4473
4474 // Clear proc cooldowns
4476}
4477
4478void Player::cooldownAddItem(ItemProperties const* itemProp, uint32_t spellIndex)
4479{
4480 if (itemProp->Spells[spellIndex].CategoryCooldown <= 0 && itemProp->Spells[spellIndex].Cooldown <= 0)
4481 return;
4482
4484 return;
4485
4486 ItemSpell const* itemSpell = &itemProp->Spells[spellIndex];
4487 uint32_t mstime = Util::getMSTime();
4488
4489 uint32_t itemSpellId = itemSpell->Id;
4490
4491 uint32_t categoryId = itemSpell->Category;
4492 int32_t categoryCooldownTime = itemSpell->CategoryCooldown;
4493
4494 if (itemSpell->CategoryCooldown > 0)
4495 _addCategoryCooldown(categoryId, categoryCooldownTime + mstime, itemSpellId, itemProp->ItemId);
4496
4497 int32_t cooldownTime = itemSpell->Cooldown;
4498 if (cooldownTime > 0)
4499 _addCooldown(COOLDOWN_TYPE_SPELL, itemSpellId, cooldownTime + mstime, itemSpellId, itemProp->ItemId);
4500}
4501
4502bool Player::cooldownCanCast(ItemProperties const* itemProp, uint32_t spellIndex)
4503{
4504 PlayerCooldownMap::iterator cooldownMapItr;
4505 ItemSpell const* itemSpell = &itemProp->Spells[spellIndex];
4506 uint32_t mstime = Util::getMSTime();
4507
4508 if (itemSpell->Category)
4509 {
4510 cooldownMapItr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].find(itemSpell->Category);
4511 if (cooldownMapItr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end())
4512 {
4513 if (mstime < cooldownMapItr->second.ExpireTime)
4514 return false;
4515
4516 m_cooldownMap[COOLDOWN_TYPE_CATEGORY].erase(cooldownMapItr);
4517 }
4518 }
4519
4520 cooldownMapItr = m_cooldownMap[COOLDOWN_TYPE_SPELL].find(itemSpell->Id);
4521 if (cooldownMapItr != m_cooldownMap[COOLDOWN_TYPE_SPELL].end())
4522 {
4523 if (mstime < cooldownMapItr->second.ExpireTime)
4524 return false;
4525
4526 m_cooldownMap[COOLDOWN_TYPE_SPELL].erase(cooldownMapItr);
4527 }
4528
4529 return true;
4530}
4531
4533{
4535 return;
4536
4537 if (const auto itemProperties = sMySQLStore.getItemProperties(m_lastPotionId))
4538 {
4539 for (uint8_t spellIndex = 0; spellIndex < MAX_ITEM_PROTO_SPELLS; ++spellIndex)
4540 {
4541 if (itemProperties->Spells[spellIndex].Id != 0 && itemProperties->Spells[spellIndex].Trigger == USE)
4542 {
4543 if (const auto* const spellInfo = sSpellMgr.getSpellInfo(itemProperties->Spells[spellIndex].Id))
4544 {
4545 cooldownAddItem(itemProperties, spellIndex);
4546 sendSpellCooldownEventPacket(spellInfo->getId());
4547 }
4548 }
4549 }
4550 }
4551
4552 m_lastPotionId = 0;
4553}
4554
4556{
4557 for (const auto& spellId : m_spellSet)
4558 {
4559 SpellInfo const* spellInfo = sSpellMgr.getSpellInfo(spellId);
4560
4561 for (uint8_t effectIndex = 0; effectIndex < 3; ++effectIndex)
4562 {
4563 if (spellInfo->getEffect(effectIndex) == SPELL_EFFECT_APPLY_AURA)
4564 {
4565 if (spellInfo->getEffectApplyAuraName(effectIndex) == auraName && spellInfo->getEffectBasePoints(effectIndex) == static_cast<int32_t>(basePoints - 1))
4566 return true;
4567 }
4568 }
4569
4570 }
4571
4572 return false;
4573}
4574
4575void Player::_addCategoryCooldown(uint32_t categoryId, uint32_t time, uint32_t SpellId, uint32_t ItemId)
4576{
4577 PlayerCooldownMap::iterator cooldownItr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].find(categoryId);
4578 if (cooldownItr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end())
4579 {
4580 auto& playerCooldown = cooldownItr->second;
4581 if (playerCooldown.ExpireTime < time)
4582 {
4583 playerCooldown.ExpireTime = time;
4584 playerCooldown.ItemId = ItemId;
4585 playerCooldown.SpellId = SpellId;
4586 }
4587 }
4588 else
4589 {
4590 PlayerCooldown playerCooldown;
4591 playerCooldown.ExpireTime = time;
4592 playerCooldown.ItemId = ItemId;
4593 playerCooldown.SpellId = SpellId;
4594
4595 m_cooldownMap[COOLDOWN_TYPE_CATEGORY].insert(std::make_pair(categoryId, playerCooldown));
4596 }
4597
4598 sLogger.debug("Player::_addCategoryCooldown added cooldown for COOLDOWN_TYPE_CATEGORY category_type {} time {} item {} spell {}", categoryId, time - Util::getMSTime(), ItemId, SpellId);
4599}
4600
4601void Player::_addCooldown(uint32_t type, uint32_t mis, uint32_t time, uint32_t SpellId, uint32_t ItemId)
4602{
4603 PlayerCooldownMap::iterator cooldownItr = m_cooldownMap[type].find(mis);
4604 if (cooldownItr != m_cooldownMap[type].end())
4605 {
4606 auto& playerCooldown = cooldownItr->second;
4607 if (playerCooldown.ExpireTime < time)
4608 {
4609 playerCooldown.ExpireTime = time;
4610 playerCooldown.ItemId = ItemId;
4611 playerCooldown.SpellId = SpellId;
4612 }
4613 }
4614 else
4615 {
4616 PlayerCooldown playerCooldown;
4617 playerCooldown.ExpireTime = time;
4618 playerCooldown.ItemId = ItemId;
4619 playerCooldown.SpellId = SpellId;
4620
4621 m_cooldownMap[type].insert(std::make_pair(mis, playerCooldown));
4622 }
4623
4624 sLogger.debug("Player::_addCooldown added cooldown for type {} misc {} time {} item {} spell {}", type, mis, time - Util::getMSTime(), ItemId, SpellId);
4625}
4626
4628{
4629 if (result == nullptr)
4630 return;
4631
4632 uint32_t mstime = Util::getMSTime();
4633
4634 do
4635 {
4636 uint32_t type = result->Fetch()[0].asUint32();
4637 uint32_t misc = result->Fetch()[1].asUint32();
4638 uint32_t rtime = result->Fetch()[2].asUint32();
4639 uint32_t spellid = result->Fetch()[3].asUint32();
4640 uint32_t itemid = result->Fetch()[4].asUint32();
4641
4642 if (type >= NUM_COOLDOWN_TYPES)
4643 continue;
4644
4645 if ((uint32_t)UNIXTIME > rtime)
4646 continue;
4647
4648 rtime -= (uint32_t)UNIXTIME;
4649
4650 if (rtime < 10)
4651 continue;
4652
4653 uint32_t realtime = mstime + ((rtime) * 1000);
4654
4655 // apply it back into cooldown map
4656 PlayerCooldown playerCooldown;
4657 playerCooldown.ExpireTime = realtime;
4658 playerCooldown.ItemId = itemid;
4659 playerCooldown.SpellId = spellid;
4660 m_cooldownMap[type].insert(std::make_pair(misc, playerCooldown));
4661
4662 } while (result->NextRow());
4663}
4664
4666{
4667 uint32_t mstime = Util::getMSTime();
4668
4669 if (buf != nullptr)
4670 buf->AddQuery("DELETE FROM playercooldowns WHERE player_guid = %u", getGuidLow());
4671 else
4672 CharacterDatabase.Execute("DELETE FROM playercooldowns WHERE player_guid = %u", getGuidLow());
4673
4674 for (uint32_t index = 0; index < NUM_COOLDOWN_TYPES; ++index)
4675 {
4676 for (PlayerCooldownMap::iterator cooldownItr = m_cooldownMap[index].begin(); cooldownItr != m_cooldownMap[index].end();)
4677 {
4678 PlayerCooldownMap::iterator nextCooldownItr = cooldownItr++;
4679
4680 if (mstime >= nextCooldownItr->second.ExpireTime)
4681 {
4682 m_cooldownMap[index].erase(nextCooldownItr);
4683 continue;
4684 }
4685
4686 if ((nextCooldownItr->second.ExpireTime - mstime) < COOLDOWN_SKIP_SAVE_IF_MS_LESS_THAN)
4687 continue;
4688
4689 uint32_t seconds = (nextCooldownItr->second.ExpireTime - mstime) / 1000;
4690
4691 if (buf != nullptr)
4692 {
4693 buf->AddQuery("INSERT INTO playercooldowns VALUES(%u, %u, %u, %u, %u, %u)", getGuidLow(),
4694 index, nextCooldownItr->first, seconds + (uint32_t)UNIXTIME, nextCooldownItr->second.SpellId, nextCooldownItr->second.ItemId);
4695 }
4696 else
4697 {
4698 CharacterDatabase.Execute("INSERT INTO playercooldowns VALUES(%u, %u, %u, %u, %u, %u)", getGuidLow(),
4699 index, nextCooldownItr->first, seconds + (uint32_t)UNIXTIME, nextCooldownItr->second.SpellId, nextCooldownItr->second.ItemId);
4700 }
4701 }
4702 }
4703}
4704
4706{
4707 for (const auto& itr : m_skills)
4708 {
4709 advanceSkillLine(itr.first, amount);
4710 }
4711}
4712
4713void Player::advanceSkillLine(uint16_t skillLine, uint16_t amount/* = 1*/)
4714{
4715 if (skillLine == 0)
4716 return;
4717
4718 auto itr = m_skills.find(skillLine);
4719 if (itr == m_skills.end() || itr->second.CurrentValue == 0)
4720 {
4721 // Add the skill line to player
4722 // addSkillLine will set correct maximum value
4723 addSkillLine(skillLine, amount, 0);
4724 sHookInterface.OnAdvanceSkillLine(this, skillLine, amount);
4725 return;
4726 }
4727
4728 uint16_t skillStep = 0;
4729 const auto currentValue = itr->second.CurrentValue;
4730
4731 const uint16_t newValue = currentValue + amount;
4732 itr->second.CurrentValue = std::min(newValue, itr->second.MaximumValue);
4733
4734 // Skill value did not change
4735 if (itr->second.CurrentValue == currentValue)
4736 return;
4737
4738 // Get skill step
4739 if (itr->second.Skill->type == SKILL_TYPE_PROFESSION || itr->second.Skill->type == SKILL_TYPE_SECONDARY)
4740 skillStep = itr->second.MaximumValue / 75U;
4741
4742 // Update skill fields
4743#if VERSION_STRING >= Cata
4744 if (itr->second.Skill->type != SKILL_TYPE_WEAPON)
4745#endif
4746 {
4747 _updateSkillFieldOnValueChange(itr->second.FieldPosition, skillStep, itr->second.CurrentValue, itr->second.MaximumValue);
4748 }
4749
4750 sHookInterface.OnAdvanceSkillLine(this, skillLine, itr->second.CurrentValue);
4751
4752#ifdef FT_ACHIEVEMENTS
4753 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, skillLine, skillStep);
4754 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skillLine, itr->second.CurrentValue);
4755#endif
4756
4757 learnSkillSpells(skillLine, itr->second.CurrentValue);
4758}
4759
4760void Player::addSkillLine(uint16_t skillLine, uint16_t currentValue, uint16_t maxValue, bool noSpellLearning/* = false*/, bool initializeProfession/* = false*/)
4761{
4762 if (skillLine == 0)
4763 return;
4764
4765 const auto skillEntry = sSkillLineStore.lookupEntry(skillLine);
4766 if (skillEntry == nullptr)
4767 return;
4768
4769 uint16_t skillStep = 0;
4770 currentValue = currentValue > DBC_PLAYER_SKILL_MAX ? DBC_PLAYER_SKILL_MAX : currentValue;
4771 maxValue = maxValue > DBC_PLAYER_SKILL_MAX ? DBC_PLAYER_SKILL_MAX : maxValue;
4772
4773 if (!initializeProfession)
4774 currentValue = currentValue < 1 ? 1U : currentValue;
4775
4776 const auto onLearnedNewSkill = [&](uint16_t curVal, uint16_t skillStep, bool isPrimaryProfession) -> void
4777 {
4778#if VERSION_STRING >= Cata
4779 // Profession skill line
4780 if (isPrimaryProfession)
4781 {
4782 if (getProfessionSkillLine(0) == 0 && getProfessionSkillLine(1) != skillLine)
4783 setProfessionSkillLine(0, skillLine);
4784 else if (getProfessionSkillLine(1) == 0 && getProfessionSkillLine(0) != skillLine)
4785 setProfessionSkillLine(1, skillLine);
4786 }
4787#endif
4788 // Set profession points
4789 if (isPrimaryProfession)
4791
4792 // Reapply skill passive auras
4793 for (const auto& aura : getAuraList())
4794 {
4795 if (aura == nullptr)
4796 continue;
4797
4798 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
4799 {
4800 const auto aurEff = aura->getAuraEffect(i);
4801 if (aurEff->getAuraEffectType() == SPELL_AURA_NONE)
4802 continue;
4803
4804 if (aurEff->getAuraEffectType() != SPELL_AURA_MOD_SKILL &&
4805 aurEff->getAuraEffectType() != SPELL_AURA_MOD_SKILL_TALENT
4806#if VERSION_STRING >= TBC
4807 && aurEff->getAuraEffectType() != SPELL_AURA_MOD_ALL_WEAPON_SKILLS
4808#endif
4809 )
4810 continue;
4811
4812 const auto effType = aurEff->getAuraEffectType();
4813 if (aurEff->getEffectMiscValue() == skillLine)
4814 aura->applyModifiers(true, effType);
4815 }
4816 }
4817
4818 if (!noSpellLearning)
4819 learnSkillSpells(skillLine, curVal);
4820
4821#ifdef FT_ACHIEVEMENTS
4822 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, skillLine, skillStep, 0);
4823 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skillLine, currentValue, 0);
4824#endif
4825 };
4826
4827 auto itr = m_skills.find(skillLine);
4828 if (itr != m_skills.end())
4829 {
4830 _verifySkillValues(skillEntry, &currentValue, &maxValue, &skillStep);
4831
4832 if (!((currentValue > itr->second.CurrentValue && maxValue >= itr->second.MaximumValue) || (currentValue == itr->second.CurrentValue && maxValue > itr->second.MaximumValue)))
4833 return;
4834
4835 itr->second.CurrentValue = currentValue;
4836 itr->second.MaximumValue = maxValue;
4837
4838 // Update skill fields
4839 _updateSkillFieldOnValueChange(itr->second.FieldPosition, skillStep, itr->second.CurrentValue, itr->second.MaximumValue);
4840
4841 if (itr->second.CurrentValue > 0)
4842 onLearnedNewSkill(itr->second.CurrentValue, skillStep, itr->second.Skill->type == SKILL_TYPE_PROFESSION);
4843 }
4844 else
4845 {
4846 // Find a skill field position for skill
4847 auto foundPosition = false;
4848 PlayerSkillFieldPosition fieldPosition;
4849 for (uint16_t i = 0; i < WOWPLAYER_SKILL_INFO_COUNT; ++i)
4850 {
4851#if VERSION_STRING >= Cata
4852 const uint16_t field = i / 2;
4853 const uint8_t offset = i & 1;
4854 if (getSkillInfoId(field, offset) == 0)
4855 {
4856 fieldPosition.field = field;
4857 fieldPosition.offset = offset;
4858 foundPosition = true;
4859 break;
4860 }
4861#else
4862 if (getSkillInfoId(i) == 0)
4863 {
4864 fieldPosition.index = i;
4865 foundPosition = true;
4866 break;
4867 }
4868#endif
4869 }
4870
4871 if (!foundPosition)
4872 {
4873 sLogger.failure("Player::addSkillLine : Could not add skill line {} to player (guid {}), skill fields are full!", skillLine, getGuidLow());
4874 return;
4875 }
4876
4877 PlayerSkill newSkill;
4878 newSkill.Skill = skillEntry;
4879 newSkill.CurrentValue = currentValue;
4880 newSkill.MaximumValue = maxValue;
4881 newSkill.FieldPosition = fieldPosition;
4882
4883 if (!initializeProfession)
4884 _verifySkillValues(skillEntry, &newSkill.CurrentValue, &newSkill.MaximumValue, &skillStep);
4885
4886 m_skills.insert(std::make_pair(skillLine, newSkill));
4887
4888 // Update skill fields
4889#if VERSION_STRING < Cata
4890 // field 0
4891 setSkillInfoId(fieldPosition.index, skillLine);
4892 setSkillInfoStep(fieldPosition.index, skillStep);
4893 // field 1
4894 setSkillInfoCurrentValue(fieldPosition.index, newSkill.CurrentValue);
4895 setSkillInfoMaxValue(fieldPosition.index, newSkill.MaximumValue);
4896#else
4897 // field 0
4898 setSkillInfoId(fieldPosition.field, fieldPosition.offset, skillLine);
4899 setSkillInfoStep(fieldPosition.field, fieldPosition.offset, skillStep);
4900 // field 1
4901 setSkillInfoCurrentValue(fieldPosition.field, fieldPosition.offset, newSkill.CurrentValue);
4902 setSkillInfoMaxValue(fieldPosition.field, fieldPosition.offset, newSkill.MaximumValue);
4903#endif
4904 // field 2
4905 _updateSkillBonusFields(fieldPosition, 0, 0);
4906
4907 if (newSkill.CurrentValue > 0)
4908 onLearnedNewSkill(newSkill.CurrentValue, skillStep, newSkill.Skill->type == SKILL_TYPE_PROFESSION);
4909 }
4910}
4911
4912bool Player::hasSkillLine(uint16_t skillLine, bool strict/* = false*/) const
4913{
4914 if (skillLine == 0)
4915 return false;
4916
4917 const auto itr = m_skills.find(skillLine);
4918 if (itr == m_skills.end())
4919 return false;
4920
4921 // Skip initialized only skills
4922 if (itr->second.CurrentValue == 0 && !strict)
4923 return false;
4924
4925 return true;
4926}
4927
4928uint16_t Player::getSkillLineCurrent(uint16_t skillLine, bool includeBonus/* = true*/) const
4929{
4930 if (skillLine == 0)
4931 return 0;
4932
4933 const auto itr = m_skills.find(skillLine);
4934 if (itr == m_skills.end())
4935 return 0;
4936
4937 if (!includeBonus)
4938 return itr->second.CurrentValue;
4939
4940 const auto result = static_cast<int32_t>(itr->second.CurrentValue) + itr->second.PermanentBonusValue + itr->second.TemporaryBonusValue;
4941 return result < 0 ? 0U : static_cast<uint16_t>(result);
4942}
4943
4945{
4946 if (skillLine == 0)
4947 return 0;
4948
4949 const auto itr = m_skills.find(skillLine);
4950 if (itr == m_skills.end())
4951 return 0;
4952
4953 return itr->second.MaximumValue;
4954}
4955
4957{
4958 for (const auto& skill : m_playerCreateInfo->skills)
4959 {
4960 if (skill.skillid == 0)
4961 continue;
4962
4963 const auto skillLine = sSkillLineStore.lookupEntry(skill.skillid);
4964 if (skillLine == nullptr)
4965 continue;
4966
4967 // Set current skill values for Death Knight's weapon skills
4968 auto curVal = skill.currentval;
4969 if (isClassDeathKnight() && skillLine->type == SKILL_TYPE_WEAPON && skillLine->id != SKILL_DUAL_WIELD)
4970 curVal = static_cast<uint16_t>((std::min(55U, getLevel()) - 1) * 5);
4971
4972 addSkillLine(skill.skillid, curVal, 0);
4973 }
4974}
4975
4976void Player::learnSkillSpells(uint16_t skillLine, uint16_t currentValue)
4977{
4978 const auto raceMask = getRaceMask();
4979 const auto classMask = getClassMask();
4980
4981 const auto skillRange = sSpellMgr.getSkillEntryRangeForSkill(skillLine);
4982 for (const auto& [_, skillEntry] : skillRange)
4983 {
4984 if (skillEntry->acquireMethod != 1 && skillEntry->acquireMethod != 2)
4985 continue;
4986
4987 // Check race mask
4988 if (skillEntry->race_mask != 0 && !(skillEntry->race_mask & raceMask))
4989 continue;
4990
4991 // Check class mask
4992 if (skillEntry->class_mask != 0 && !(skillEntry->class_mask & classMask))
4993 continue;
4994
4995 // Check skill value
4996 if (currentValue < skillEntry->minSkillLineRank)
4997 continue;
4998
4999 // Add automatically acquired spells
5000 addSpell(skillEntry->spell, skillLine);
5001 }
5002}
5003
5004void Player::modifySkillBonus(uint16_t skillLine, int16_t amount, bool permanentBonus)
5005{
5006 if (skillLine == 0)
5007 return;
5008
5009 auto itr = m_skills.find(skillLine);
5010 if (itr == m_skills.end() || itr->second.CurrentValue == 0)
5011 return;
5012
5013 if (permanentBonus)
5014 itr->second.PermanentBonusValue += amount;
5015 else
5016 itr->second.TemporaryBonusValue += amount;
5017
5018 // Bonuses can be negative but client still wants them in unsigned
5019 _updateSkillBonusFields(itr->second.FieldPosition, static_cast<uint16_t>(itr->second.TemporaryBonusValue), static_cast<uint16_t>(itr->second.PermanentBonusValue));
5020}
5021
5023{
5024 if (skillLine == 0)
5025 return;
5026
5027 auto itr = m_skills.find(skillLine);
5028 if (itr == m_skills.end())
5029 return;
5030
5031 const auto oldCurValue = itr->second.CurrentValue;
5032 const auto oldMaxValue = itr->second.MaximumValue;
5033 itr->second.MaximumValue = maxValue;
5034
5035 auto valuesChanged = false;
5036 uint16_t skillStep = 0;
5037
5038 _verifySkillValues(itr->second.Skill, &itr->second.CurrentValue, &itr->second.MaximumValue, &skillStep, &valuesChanged);
5039
5040 if (oldMaxValue != itr->second.MaximumValue || valuesChanged)
5041 {
5042 // Update skill fields
5043#if VERSION_STRING >= Cata
5044 if (itr->second.Skill->type != SKILL_TYPE_WEAPON)
5045#endif
5046 {
5047 _updateSkillFieldOnValueChange(itr->second.FieldPosition, skillStep, itr->second.CurrentValue, itr->second.MaximumValue);
5048 }
5049
5050#ifdef FT_ACHIEVEMENTS
5051 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, skillLine, skillStep, 0);
5052#endif
5053
5054 // Current skill value did not change
5055 if (oldCurValue == itr->second.CurrentValue)
5056 return;
5057
5058 sHookInterface.OnAdvanceSkillLine(this, skillLine, itr->second.CurrentValue);
5059
5060#ifdef FT_ACHIEVEMENTS
5061 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skillLine, itr->second.CurrentValue, 0);
5062#endif
5063
5064 learnSkillSpells(skillLine, itr->second.CurrentValue);
5065 }
5066}
5067
5069{
5070 if (skillLine == 0)
5071 return;
5072
5073 auto itr = m_skills.find(skillLine);
5074 if (itr == m_skills.end())
5075 return;
5076
5077 const auto fieldPosition = itr->second.FieldPosition;
5078
5079 if (itr->second.Skill->type == SKILL_TYPE_PROFESSION)
5081
5082#if VERSION_STRING >= Cata
5083 // Clear profession skill line
5084 if (getProfessionSkillLine(0) == itr->second.Skill->id)
5086 else if (getProfessionSkillLine(1) == itr->second.Skill->id)
5088
5089 // Since cata, profession skills are never actually removed, they are only "deactivated"
5090 if (itr->second.Skill->type == SKILL_TYPE_PROFESSION || itr->second.Skill->type == SKILL_TYPE_SECONDARY)
5091 {
5092 itr->second.MaximumValue = 75;
5093 itr->second.CurrentValue = 0;
5094 itr->second.TemporaryBonusValue = 0;
5095 itr->second.PermanentBonusValue = 0;
5096 }
5097 else
5098#endif
5099 {
5100 m_skills.erase(itr);
5101 }
5102
5103 // Update skill fields
5104#if VERSION_STRING < Cata
5105 // field 0
5106 setSkillInfoId(fieldPosition.index, 0);
5107 setSkillInfoStep(fieldPosition.index, 0);
5108 // field 1
5109 setSkillInfoCurrentValue(fieldPosition.index, 0);
5110 setSkillInfoMaxValue(fieldPosition.index, 0);
5111#else
5112 // field 0
5113 setSkillInfoStep(fieldPosition.field, fieldPosition.offset, 0);
5114 // field 1
5115 setSkillInfoCurrentValue(fieldPosition.field, fieldPosition.offset, 0);
5116 setSkillInfoMaxValue(fieldPosition.field, fieldPosition.offset, 0);
5117#endif
5118 // field 2
5119 _updateSkillBonusFields(fieldPosition, 0, 0);
5120
5121 // Deactivate passive skill bonus auras
5122 for (const auto& aurEff : getAuraEffectList(SPELL_AURA_MOD_SKILL))
5123 {
5124 if (aurEff->getEffectMiscValue() == skillLine)
5125 {
5126 auto modifiableAurEff = aurEff->getAura()->getModifiableAuraEffect(aurEff->getEffectIndex());
5127 modifiableAurEff->setEffectActive(false);
5128 }
5129 }
5130
5131 // Deactivate passive skill bonus auras
5132 for (const auto& aurEff : getAuraEffectList(SPELL_AURA_MOD_SKILL_TALENT))
5133 {
5134 if (aurEff->getEffectMiscValue() == skillLine)
5135 {
5136 auto modifiableAurEff = aurEff->getAura()->getModifiableAuraEffect(aurEff->getEffectIndex());
5137 modifiableAurEff->setEffectActive(false);
5138 }
5139 }
5140
5141 // Remove skill spells
5142 removeSkillSpells(skillLine);
5143}
5144
5146{
5147 const auto skillRange = sSpellMgr.getSkillEntryRangeForSkill(skillLine);
5148 for (const auto& [_, skillEntry] : skillRange)
5149 {
5150 // Check also from deleted spells
5151 if (!removeSpell(skillEntry->spell, false))
5152 removeDeletedSpell(skillEntry->spell);
5153 }
5154}
5155
5157{
5158 for (auto itr = m_skills.cbegin(); itr != m_skills.cend();)
5159 {
5160 const auto itr2 = itr;
5161 ++itr;
5162
5163 // Skill is not necessarily erased from skill map
5164 removeSkillLine(itr2->first);
5165 }
5166}
5167
5169{
5170 for (auto& itr : m_skills)
5171 {
5172 // Skip initialized only values
5173 if (itr.second.CurrentValue == 0)
5174 continue;
5175
5176 auto valuesChanged = false;
5177 uint16_t skillStep = 0;
5178
5179 _verifySkillValues(itr.second.Skill, &itr.second.CurrentValue, &itr.second.MaximumValue, &skillStep, &valuesChanged);
5180
5181 // Update skill fields
5182#if VERSION_STRING < Cata
5183 if (valuesChanged)
5184#else
5185 if (valuesChanged && itr.second.Skill->type != SKILL_TYPE_WEAPON)
5186#endif
5187 _updateSkillFieldOnValueChange(itr.second.FieldPosition, skillStep, itr.second.CurrentValue, itr.second.MaximumValue);
5188 }
5189}
5190
5192{
5193 SkillMap::iterator itr = m_skills.find(id);
5194 if (itr == m_skills.end())
5195 return 0.0f;
5196
5197 return itr->second.GetSkillUpChance();
5198}
5199
5200#if VERSION_STRING >= Cata
5202{
5203 // Since cata player must have profession skills initialized even if the player does not have them
5204#if VERSION_STRING == Cata
5205 for (uint16_t skillId = SKILL_FROST; skillId != SKILL_PET_HYDRA; ++skillId)
5206#elif VERSION_STRING == Mop
5207 for (uint16_t skillId = SKILL_SWORDS; skillId != SKILL_DIREHORN; ++skillId)
5208#endif
5209 {
5210 const auto skillLine = sSkillLineStore.lookupEntry(skillId);
5211 if (skillLine == nullptr)
5212 continue;
5213
5214 if (skillLine->type != SKILL_TYPE_PROFESSION && skillLine->type != SKILL_TYPE_SECONDARY)
5215 continue;
5216
5217 if (!hasSkillLine(skillId, true))
5218 addSkillLine(skillId, 0, 0, false, true);
5219 }
5220}
5221#endif
5222
5227
5229{
5230 armorProficiency |= proficiency;
5231}
5232
5234{
5235 armorProficiency &= ~proficiency;
5236}
5237
5242
5244{
5245 weaponProficiency |= proficiency;
5246}
5247
5249{
5250 weaponProficiency &= ~proficiency;
5251}
5252
5253void Player::applyItemProficienciesFromSpell(SpellInfo const* spellInfo, bool apply)
5254{
5255 if (spellInfo == nullptr)
5256 return;
5257
5258 uint16_t skillId = 0;
5259 const auto skill_line_ability = sSpellMgr.getFirstSkillEntryForSpell(spellInfo->getId());
5260 if (skill_line_ability != nullptr)
5261 skillId = static_cast<uint16_t>(skill_line_ability->skilline);
5262
5263 const auto skill_line = sSkillLineStore.lookupEntry(skillId);
5264 if (skill_line == nullptr)
5265 return;
5266
5267 const auto subclass = spellInfo->getEquippedItemSubClass();
5268 if (apply)
5269 {
5270 // Add the skill to player if player does not have it
5271 // addSkillLine will set correct maximum skill value
5272 if (!hasSkillLine(skillId))
5273 addSkillLine(skillId, 1, 0);
5274
5275 if (spellInfo->getEquippedItemClass() == ITEM_CLASS_ARMOR && !(getArmorProficiency() & subclass))
5276 {
5277 addArmorProficiency(subclass);
5279 }
5280 else if (spellInfo->getEquippedItemClass() == ITEM_CLASS_WEAPON && !(getWeaponProficiency() & subclass))
5281 {
5282 addWeaponProficiency(subclass);
5284 }
5285 }
5286 else
5287 {
5288 if (hasSkillLine(skillId))
5289 removeSkillLine(skillId);
5290
5291 if (spellInfo->getEquippedItemClass() == ITEM_CLASS_ARMOR && getArmorProficiency() & subclass)
5292 {
5293 removeArmorProficiency(subclass);
5295 }
5296 else if (spellInfo->getEquippedItemClass() == ITEM_CLASS_WEAPON && getWeaponProficiency() & subclass)
5297 {
5298 removeWeaponProficiency(subclass);
5300 }
5301 }
5302}
5303
5304#ifdef FT_GLYPHS
5305void Player::updateGlyphs()
5306{
5307#if VERSION_STRING == WotLK
5308 for (uint32_t i = 0; i < sGlyphSlotStore.getNumRows(); ++i)
5309 {
5310 const auto glyphSlot = sGlyphSlotStore.lookupEntry(i);
5311 if (glyphSlot == nullptr)
5312 continue;
5313
5314 if (glyphSlot->Slot > 0)
5315 setGlyphSlot(static_cast<uint16_t>(glyphSlot->Slot - 1), glyphSlot->Id);
5316 }
5317#else
5318 uint16_t slot = 0;
5319 for (uint32_t i = 0; i < sGlyphSlotStore.getNumRows(); ++i)
5320 {
5321 const auto glyphSlot = sGlyphSlotStore.lookupEntry(i);
5322 if (glyphSlot != nullptr)
5323 setGlyphSlot(slot++, glyphSlot->Id);
5324 }
5325#endif
5326
5327 const auto level = getLevel();
5328 uint32_t slotMask = 0;
5329
5330#if VERSION_STRING == WotLK
5331 if (level >= 15)
5332 slotMask |= (GS_MASK_1 | GS_MASK_2);
5333 if (level >= 30)
5334 slotMask |= GS_MASK_3;
5335 if (level >= 50)
5336 slotMask |= GS_MASK_4;
5337 if (level >= 70)
5338 slotMask |= GS_MASK_5;
5339 if (level >= 80)
5340 slotMask |= GS_MASK_6;
5341#elif VERSION_STRING == Cata
5342 if (level >= 25)
5343 slotMask |= GS_MASK_LEVEL_25;
5344 if (level >= 50)
5345 slotMask |= GS_MASK_LEVEL_50;
5346 if (level >= 75)
5347 slotMask |= GS_MASK_LEVEL_75;
5348#elif VERSION_STRING == Mop
5349 // TODO
5350#endif
5351
5352 setGlyphsEnabled(slotMask);
5353}
5354#endif
5355
5357{
5358 return m_comboTarget;
5359}
5360
5362{
5363 return m_comboPoints;
5364}
5365
5367{
5368 // Remove combo point retain auras
5369 // This will not clear points created by retain aura, remove code checks for duration
5370 if (points > 0)
5372
5373 if (getComboPointTarget() == targetGuid)
5374 {
5375 m_comboPoints += points;
5376 }
5377 else
5378 {
5379 // Clear points when switching combo target
5380 m_comboTarget = targetGuid;
5381 m_comboPoints = points;
5382 }
5383
5385}
5386
5388{
5389 if (getComboPoints() > 5)
5390 m_comboPoints = 5;
5391
5392 if (getComboPoints() < 0)
5393 m_comboPoints = 0;
5394
5395 // todo: I think there should be a better way to do this, copypasting from legacy method now -Appled
5396 unsigned char buffer[10];
5397 uint16_t length = 2;
5398
5399 if (getComboPointTarget() != 0)
5400 {
5401 const auto* const target = getWorldMapUnit(getComboPointTarget());
5402 if (target == nullptr || target->isDead() || getTargetGuid() != getComboPointTarget())
5403 {
5404 buffer[0] = buffer[1] = 0;
5405 }
5406 else
5407 {
5408 length = static_cast<uint16_t>(FastGUIDPack(getComboPointTarget(), buffer, 0));
5409 buffer[length++] = getComboPoints();
5410 }
5411 }
5412 else
5413 {
5414 buffer[0] = buffer[1] = 0;
5415 }
5416
5418}
5419
5421{
5422 m_comboTarget = 0;
5423 m_comboPoints = 0;
5424
5425 // Remove combo point retain auras when combo points have been used
5427
5429}
5430
5431void Player::_addSpell(uint32_t spellId, uint16_t fromSkill/* = 0*/, bool learningPreviousRanks/* = false*/, bool ignorePreviousRanks/* = false*/)
5432{
5433 const auto* spellInfo = sSpellMgr.getSpellInfo(spellId);
5434 if (spellInfo == nullptr)
5435 return;
5436
5437 if (sSpellMgr.isSpellDisabled(spellId))
5438 return;
5439
5440 // Check if player already knows this spell
5441 if (hasSpell(spellId))
5442 return;
5443
5444 if (spellInfo->hasSpellRanks())
5445 {
5446 if (!learningPreviousRanks)
5447 {
5448 // Check if player has at one point known a higher rank of this spell
5449 const auto* higherRankInfo = spellInfo->getRankInfo()->getLastSpell();
5450 const auto isSingleRankAbility = spellInfo->canKnowOnlySingleRank();
5451 do
5452 {
5453 // If player can know only one rank of this spell rank chain, try find a existing higher rank
5454 // Possible lower ranks are removed when a higher rank is added to spell map
5455 if (isSingleRankAbility && hasSpell(higherRankInfo->getId()))
5456 return;
5457
5458 if (removeDeletedSpell(higherRankInfo->getId()))
5459 {
5460 // Possibly found a deleted higher rank, add it to player instead
5461 break;
5462 }
5463
5464 if (higherRankInfo->getId() == spellId)
5465 break;
5466
5467 higherRankInfo = higherRankInfo->getRankInfo()->getPreviousSpell();
5468 } while (higherRankInfo != nullptr);
5469
5470 if (higherRankInfo != nullptr)
5471 spellInfo = higherRankInfo;
5472 }
5473 else
5474 {
5475 // When learning previous ranks or talents make sure they are also deleted from deleted spells
5476 removeDeletedSpell(spellInfo->getId());
5477 }
5478
5479 if (!ignorePreviousRanks && !spellInfo->isTalent() && !spellInfo->canKnowOnlySingleRank())
5480 {
5481 // Add all previous ranks to player
5482 if (const auto* const previousSpell = spellInfo->getRankInfo()->getPreviousSpell())
5483 _addSpell(previousSpell->getId(), fromSkill, true);
5484 }
5485 }
5486 else
5487 {
5488 // Check if spell was deleted from player
5489 removeDeletedSpell(spellId);
5490 }
5491
5492 uint32_t supercededSpellId = 0;
5493 if (spellInfo->hasSpellRanks() && (spellInfo->canKnowOnlySingleRank() || spellInfo->isTalent()))
5494 {
5495 // If spell can have only one rank known move all previous ranks to deleted spells
5496 const auto* previousRank = spellInfo->getRankInfo()->getPreviousSpell();
5497 const auto moveToDeleted = !spellInfo->isTalent();
5498 const auto silently = !spellInfo->isTalent();
5499 while (previousRank != nullptr)
5500 {
5501 if (_removeSpell(previousRank->getId(), moveToDeleted, silently, true))
5502 {
5503 if (!spellInfo->isTalent())
5504 supercededSpellId = previousRank->getId();
5505 break;
5506 }
5507
5508 previousRank = previousRank->getRankInfo()->getPreviousSpell();
5509 }
5510 }
5511
5512 m_spellSet.emplace(spellInfo->getId());
5513
5514 if (IsInWorld())
5515 {
5516 if (!ignorePreviousRanks)
5517 {
5518 // If previous rank was found overwrite it in client with smsg_superceded packet
5519 if (supercededSpellId > 0)
5520 getSession()->SendPacket(SmsgSupercededSpell(supercededSpellId, spellInfo->getId()).serialise().get());
5521 else
5522 getSession()->SendPacket(SmsgLearnedSpell(spellInfo->getId()).serialise().get());
5523 }
5524
5525 // Cast talents and auto castable spells with learn spell effect
5526 if ((spellInfo->isTalent() || spellInfo->getAttributesEx() & ATTRIBUTESEX_AUTOCASTED_AT_SPELL_LEARN) && spellInfo->hasEffect(SPELL_EFFECT_LEARN_SPELL))
5527 {
5528 castSpell(getGuid(), spellInfo, true);
5529 }
5530 // Cast passive spells only if player has proper shapeshift form
5531 else if (spellInfo->isPassive())
5532 {
5533 if (spellInfo->getRequiredShapeShift() == 0 ||
5534 (getShapeShiftMask() != 0 && (spellInfo->getRequiredShapeShift() & getShapeShiftMask())) ||
5535 (getShapeShiftMask() == 0 && (spellInfo->getAttributesExB() & ATTRIBUTESEXB_NOT_NEED_SHAPESHIFT)))
5536 {
5537 // TODO: temporarily check for this custom flag, will be removed when spell system handles pets properly!
5538 if (((spellInfo->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET) == 0) || (spellInfo->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET && getPet() != nullptr))
5539 castSpell(getGuid(), spellInfo, true);
5540 }
5541 }
5542 }
5543
5544 // Add spell's skill line to player
5545 if (fromSkill == 0)
5546 {
5547 const auto teachesProfession = spellInfo->hasEffect(SPELL_EFFECT_SKILL) || spellInfo->hasEffect(SPELL_EFFECT_TRADE_SKILL);
5548 const auto raceMask = getRaceMask();
5549 const auto classMask = getClassMask();
5550
5551 const auto spellSkillRange = sSpellMgr.getSkillEntryRangeForSpell(spellId);
5552 for (const auto& [_, skillEntry] : spellSkillRange)
5553 {
5554 if (skillEntry->race_mask > 0 && !(skillEntry->race_mask & raceMask))
5555 continue;
5556
5557 if (skillEntry->class_mask > 0 && !(skillEntry->class_mask & classMask))
5558 continue;
5559
5560 const auto skillLine = static_cast<uint16_t>(skillEntry->skilline);
5561 if (hasSkillLine(skillLine))
5562 continue;
5563
5564 // Do not learn skill default spells if spell does not teach profession skills
5565 // This allows to make starting spells fully customizable
5566 // If skill default spells would be taught, then all default starting spells from DBC files are taught on first login
5567 addSkillLine(skillLine, 1, 0, !teachesProfession);
5568 }
5569 }
5570
5571#ifdef FT_ACHIEVEMENTS
5572 if (!IsInWorld())
5573 return;
5574
5575 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spellId, 1, 0);
5576 if (spellInfo->getMechanicsType() == MECHANIC_MOUNTED) // Mounts
5577 {
5578 // miscvalue1==777 for mounts, 778 for pets
5579 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS, 777, 0, 0);
5580 }
5581 else if (spellInfo->getEffect(0) == SPELL_EFFECT_SUMMON) // Companion pet?
5582 {
5583 // miscvalue1==777 for mounts, 778 for pets
5584 // make sure it's a companion pet, not some other summon-type spell
5585 if (const auto summonProperties = sSummonPropertiesStore.lookupEntry(spellInfo->getEffectMiscValueB(0)))
5586 {
5587 if (summonProperties->Slot == 5 || (summonProperties->Type == SUMMON_TYPE_COMPANION && summonProperties->Slot != 6))
5588 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS, 778, 0, 0);
5589 }
5590 }
5591#endif
5592}
5593
5594bool Player::_removeSpell(uint32_t spellId, bool moveToDeleted, bool silently/* = false*/, bool removingPreviousRank/* = false*/, bool forceRemoveHigherRanks/* = false*/)
5595{
5596 const auto itr = std::as_const(m_spellSet).find(spellId);
5597 if (itr == m_spellSet.cend())
5598 {
5599 // When resetting talents if player can know single rank of this spell and the first rank is a talent,
5600 // other ranks are never removed since player does not have first rank active anymore
5601 if (forceRemoveHigherRanks)
5602 {
5603 const auto* const spellInfo = sSpellMgr.getSpellInfo(spellId);
5604 if (spellInfo == nullptr || !spellInfo->hasSpellRanks() || !spellInfo->canKnowOnlySingleRank())
5605 return false;
5606
5607 const auto* higherRankInfo = spellInfo->getRankInfo()->getNextSpell();
5608 while (higherRankInfo != nullptr)
5609 {
5610 if (_removeSpell(higherRankInfo->getId(), true, silently, true))
5611 {
5612 // Removed a higher ranked spell from single rank chain, safe to exit
5613 return true;
5614 }
5615
5616 higherRankInfo = higherRankInfo->getRankInfo()->getNextSpell();
5617 }
5618 }
5619
5620 return false;
5621 }
5622
5623 m_spellSet.erase(itr);
5625
5626 if (moveToDeleted)
5627 m_deletedSpellSet.emplace(spellId);
5628
5629 const auto* const spellInfo = sSpellMgr.getSpellInfo(spellId);
5630 auto activatedPreviousRank = false;
5631 if (spellInfo->hasSpellRanks())
5632 {
5633 // If player can know single rank of this spell rank chain, activate previous rank in spell map
5634 if (!removingPreviousRank && spellInfo->canKnowOnlySingleRank())
5635 {
5636 const auto* previousSpell = spellInfo->getRankInfo()->getPreviousSpell();
5637 while (previousSpell != nullptr)
5638 {
5639 if (hasDeletedSpell(previousSpell->getId()))
5640 {
5641 _addSpell(previousSpell->getId(), 0, true, true);
5642 activatedPreviousRank = true;
5643 break;
5644 }
5645 previousSpell = previousSpell->getRankInfo()->getPreviousSpell();
5646 }
5647
5648 if (IsInWorld() && !silently && activatedPreviousRank)
5649 getSession()->SendPacket(SmsgSupercededSpell(spellId, previousSpell->getId()).serialise().get());
5650 }
5651 }
5652
5653 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
5654 {
5655 const auto spellEff = spellInfo->getEffect(i);
5656 if (spellEff == SPELL_EFFECT_NULL)
5657 continue;
5658
5659 switch (spellEff)
5660 {
5662 // If spell teaches another spell, remove it recursively as well
5663 if (const auto taughtSpellId = spellInfo->getEffectTriggerSpell(i))
5664 _removeSpell(taughtSpellId, false, false, true);
5665 break;
5667 setDualWield(false);
5668 break;
5670 applyItemProficienciesFromSpell(spellInfo, false);
5671 break;
5673 if (const auto triggerSpellId = spellInfo->getEffectTriggerSpell(i))
5674 removeAllAurasByIdForGuid(triggerSpellId, getGuid());
5675 break;
5676#if VERSION_STRING >= WotLK
5678 setDualWield2H(false);
5679 break;
5680#endif
5681 default:
5682 break;
5683 }
5684 }
5685
5686 if (IsInWorld() && !silently && !activatedPreviousRank)
5687 getSession()->SendPacket(SmsgRemovedSpell(spellId).serialise().get());
5688
5689 if (spellInfo->hasSpellRanks())
5690 {
5691 // Remove higher ranks from spell map as well
5692 if (const auto* const nextSpell = spellInfo->getRankInfo()->getNextSpell())
5693 _removeSpell(nextSpell->getId(), true, false, true);
5694 }
5695
5696 return true;
5697}
5698
5699
5700void Player::_verifySkillValues(WDB::Structures::SkillLineEntry const* skillEntry, uint16_t* currentValue, uint16_t* maxValue, uint16_t* skillStep, bool* requireUpdate)
5701{
5702 auto level_bound_skill = skillEntry->type == SKILL_TYPE_WEAPON && skillEntry->id != SKILL_DUAL_WIELD;
5703#if VERSION_STRING <= WotLK
5704 level_bound_skill = level_bound_skill || skillEntry->id == SKILL_LOCKPICKING;
5705#endif
5706#if VERSION_STRING <= TBC
5707 level_bound_skill = level_bound_skill || skillEntry->id == SKILL_POISONS;
5708#endif
5709
5710 uint16_t newMaximum = 0;
5711 auto isCurrentValueMaxed = false;
5712 *requireUpdate = false;
5713
5714 if (level_bound_skill)
5715 {
5716 newMaximum = static_cast<uint16_t>(5 * getLevel());
5717#if VERSION_STRING >= Cata
5718 // In cata all weapon skills are always maxed
5719 isCurrentValueMaxed = true;
5720#endif
5721 }
5722 else if (skillEntry->type == SKILL_TYPE_LANGUAGE)
5723 {
5724 newMaximum = 300;
5725 isCurrentValueMaxed = true;
5726 }
5727 else if (skillEntry->type == SKILL_TYPE_PROFESSION || skillEntry->type == SKILL_TYPE_SECONDARY)
5728 {
5729 newMaximum = *maxValue;
5730
5731 if (newMaximum == 0)
5732 {
5733 newMaximum = 75;
5734 while (newMaximum < *currentValue && newMaximum < DBC_PLAYER_SKILL_MAX)
5735 {
5736 newMaximum += 75;
5737 }
5738 }
5739
5740 if (skillEntry->id == SKILL_RIDING)
5741 isCurrentValueMaxed = true;
5742 }
5743 else
5744 {
5745 newMaximum = 1;
5746 isCurrentValueMaxed = true;
5747 }
5748
5749 // force to be within limits
5750 if (newMaximum > DBC_PLAYER_SKILL_MAX)
5751 newMaximum = DBC_PLAYER_SKILL_MAX;
5752
5753 if (*maxValue != newMaximum)
5754 {
5755 *requireUpdate = true;
5756 *maxValue = newMaximum;
5757 }
5758 if (*currentValue > newMaximum)
5759 {
5760 *requireUpdate = true;
5761 *currentValue = newMaximum;
5762 }
5763
5764 // These are at max value all the time
5765 if (isCurrentValueMaxed && *currentValue != newMaximum)
5766 {
5767 *requireUpdate = true;
5768 *currentValue = newMaximum;
5769 }
5770
5771 if (skillEntry->type == SKILL_TYPE_PROFESSION || skillEntry->type == SKILL_TYPE_SECONDARY)
5772 *skillStep = *maxValue / 75U;
5773 else
5774 *skillStep = 0;
5775}
5776
5777void Player::_verifySkillValues(WDB::Structures::SkillLineEntry const* skillEntry, uint16_t* currentValue, uint16_t* maxValue, uint16_t* skillStep)
5778{
5779 auto requireUpdate = false;
5780 _verifySkillValues(skillEntry, currentValue, maxValue, skillStep, &requireUpdate);
5781}
5782
5783void Player::_updateSkillFieldOnValueChange(const PlayerSkillFieldPosition fieldPosition, uint16_t skillStep, uint16_t currentValue, uint16_t maxValue)
5784{
5785#if VERSION_STRING < Cata
5786 // field 0
5787 setSkillInfoStep(fieldPosition.index, skillStep);
5788 // field 1
5789 setSkillInfoCurrentValue(fieldPosition.index, currentValue);
5790 setSkillInfoMaxValue(fieldPosition.index, maxValue);
5791#else
5792 // field 0
5793 setSkillInfoStep(fieldPosition.field, fieldPosition.offset, skillStep);
5794 // field 1
5795 setSkillInfoCurrentValue(fieldPosition.field, fieldPosition.offset, currentValue);
5796 setSkillInfoMaxValue(fieldPosition.field, fieldPosition.offset, maxValue);
5797#endif
5798}
5799
5800void Player::_updateSkillBonusFields(const PlayerSkillFieldPosition fieldPosition, uint16_t tempBonus, uint16_t permBonus)
5801{
5802#if VERSION_STRING < Cata
5803 // field 2
5804 setSkillInfoBonusTemporary(fieldPosition.index, tempBonus);
5805 setSkillInfoBonusPermanent(fieldPosition.index, permBonus);
5806#else
5807 // field 2
5808 setSkillInfoBonusTemporary(fieldPosition.field, fieldPosition.offset, tempBonus);
5809 setSkillInfoBonusPermanent(fieldPosition.field, fieldPosition.offset, permBonus);
5810#endif
5811}
5812
5813//////////////////////////////////////////////////////////////////////////////////////////
5814// Talents
5815void Player::learnTalent(uint32_t talentId, uint32_t talentRank)
5816{
5817 auto curTalentPoints = getActiveSpec().getTalentPoints();
5818 if (curTalentPoints == 0)
5819 return;
5820
5821 if (talentRank > 4)
5822 return;
5823
5824 auto talentInfo = sTalentStore.lookupEntry(talentId);
5825 if (talentInfo == nullptr)
5826 return;
5827#if VERSION_STRING < Mop
5828 if (sSpellMgr.isSpellDisabled(talentInfo->RankID[talentRank]))
5829 {
5830 if (IsInWorld())
5831 sendCastFailedPacket(talentInfo->RankID[talentRank], SPELL_FAILED_SPELL_UNAVAILABLE, 0, 0);
5832 return;
5833 }
5834
5835 // Check if player already has the talent with same or higher rank
5836 for (auto i = talentRank; i <= 4; ++i)
5837 {
5838 if (talentInfo->RankID[i] != 0 && hasSpell(talentInfo->RankID[i]))
5839 return;
5840 }
5841
5842 // Check if talent tree is for player's class
5843 auto talentTreeInfo = sTalentTabStore.lookupEntry(talentInfo->TalentTree);
5844 if (talentTreeInfo == nullptr || !(getClassMask() & talentTreeInfo->ClassMask))
5845 return;
5846
5847#if VERSION_STRING >= Cata
5848 // Check if enough talent points are spent in the primary talent tree before unlocking other trees
5849 if (talentInfo->TalentTree != m_FirstTalentTreeLock && m_FirstTalentTreeLock != 0)
5850 {
5851 auto pointsUsed = 0;
5852 for (const auto& [talentId, rank] : getActiveSpec().getTalents())
5853 {
5854 pointsUsed += rank + 1;
5855 }
5856
5857 // You need to spent 31 points in the primary tree before you're able to unlock other trees
5858 if (pointsUsed < 31)
5859 return;
5860 }
5861#endif
5862
5863 // Check if talent requires another talent
5864 if (talentInfo->DependsOn > 0)
5865 {
5866 auto dependsOnTalent = sTalentStore.lookupEntry(talentInfo->DependsOn);
5867 if (dependsOnTalent != nullptr)
5868 {
5869 auto hasEnoughRank = false;
5870 for (auto i = 0; i <= 4; ++i)
5871 {
5872 if (dependsOnTalent->RankID[i] != 0)
5873 {
5874 if (hasSpell(dependsOnTalent->RankID[i]))
5875 {
5876 hasEnoughRank = true;
5877 break;
5878 }
5879 }
5880 }
5881 if (!hasEnoughRank)
5882 return;
5883 }
5884 }
5885
5886 auto spellId = talentInfo->RankID[talentRank];
5887 if (spellId == 0)
5888 {
5889 sLogger.info("Player::learnTalent: Player tried to learn talent {} (rank {}) but talent's spell id is 0.", talentId, talentRank);
5890 return;
5891 }
5892
5893 // Check can player yet access this talent
5894 uint32_t spentPoints = 0;
5895 if (talentInfo->Row > 0)
5896 {
5897 // Loop through player's talents
5898 for (const auto& [talent, rank] : getActiveSpec().getTalents())
5899 {
5900 auto tmpTalent = sTalentStore.lookupEntry(talent);
5901 if (tmpTalent == nullptr)
5902 continue;
5903 // Skip talents from other trees
5904 if (tmpTalent->TalentTree != talentInfo->TalentTree)
5905 continue;
5906 spentPoints += rank + 1;
5907 }
5908 }
5909
5910 if (spentPoints < (talentInfo->Row * 5))
5911 return;
5912
5913 // Get current talent rank
5914 uint8_t curTalentRank = 0;
5915 auto isMultiRankTalent = false;
5916 for (int8_t _talentRank = 4; _talentRank >= 0; --_talentRank)
5917 {
5918 if (talentInfo->RankID[_talentRank] != 0)
5919 {
5920 if (_talentRank > 0)
5921 isMultiRankTalent = true;
5922
5923 if (hasSpell(talentInfo->RankID[_talentRank]))
5924 {
5925 curTalentRank = _talentRank + 1;
5926 break;
5927 }
5928 }
5929 }
5930
5931 // Check does player have enough talent points
5932 auto requiredTalentPoints = (talentRank + 1) - curTalentRank;
5933 if (curTalentPoints < requiredTalentPoints)
5934 return;
5935
5936 // Check if player already knows this or higher rank
5937 if (curTalentRank >= (talentRank + 1))
5938 return;
5939
5940 // Check if player already has the talent spell
5941 if (hasSpell(spellId))
5942 return;
5943
5944 const auto spellInfo = sSpellMgr.getSpellInfo(spellId);
5945 if (spellInfo == nullptr)
5946 return;
5947
5948 _addSpell(spellId, 0, isMultiRankTalent);
5949
5950#if VERSION_STRING >= Cata
5951 // Set primary talent tree and lock others
5952 if (m_FirstTalentTreeLock == 0)
5953 {
5954 m_FirstTalentTreeLock = talentInfo->TalentTree;
5955 // TODO: learning Mastery and spec spells
5956 // also need to handle them in talent reset
5957 }
5958#endif
5959
5960 // Add the new talent to player talent map
5961 getActiveSpec().addTalent(talentId, static_cast<uint8_t>(talentRank));
5962 setTalentPoints(curTalentPoints - requiredTalentPoints, false);
5963#endif
5964}
5965
5967{
5968#if VERSION_STRING < Mop
5969 // Loop through player's talents
5970 for (const auto& [talentId, rank] : getActiveSpec().getTalents())
5971 {
5972 if (const auto* tmpTalent = sTalentStore.lookupEntry(talentId))
5973 _removeSpell(tmpTalent->RankID[rank], false, false, true, true);
5974 }
5975
5976 // Unsummon current pet or set temporarily unsummoned pet offline
5977 if (getPet() != nullptr)
5978 getPet()->unSummon();
5979 else
5981
5982 // Check offhand
5984
5985 // Clear talents
5987#if VERSION_STRING >= Cata
5989#endif
5990
5991 // Reset talent point amount
5993#endif
5994}
5995
5997{
5998 if (m_talentSpecsCount == 1)
5999 {
6000 resetTalents();
6001 return;
6002 }
6003
6004 const auto activeSpec = m_talentActiveSpec;
6005 resetTalents();
6006
6007 if (activeSpec == SPEC_PRIMARY)
6009 else
6011
6012 resetTalents();
6013 // Change back to the original spec
6014 activateTalentSpec(activeSpec);
6015}
6016
6017void Player::setTalentPoints(uint32_t talentPoints, bool forBothSpecs /*= true*/)
6018{
6019 if (!forBothSpecs)
6020 getActiveSpec().setTalentPoints(talentPoints);
6021 else
6022 {
6023#ifndef FT_DUAL_SPEC
6024 getActiveSpec().setTalentPoints(talentPoints);
6025#else
6026 m_specs[SPEC_PRIMARY].setTalentPoints(talentPoints);
6027 m_specs[SPEC_SECONDARY].setTalentPoints(talentPoints);
6028#endif
6029 }
6030
6031#if VERSION_STRING < Cata
6032 // Send talent points also to client
6033 setFreeTalentPoints(talentPoints);
6034#endif
6035}
6036
6037void Player::addTalentPoints(uint32_t talentPoints, bool forBothSpecs /*= true*/)
6038{
6039 if (!forBothSpecs)
6040 setTalentPoints(getActiveSpec().getTalentPoints() + talentPoints);
6041 else
6042 {
6043#ifndef FT_DUAL_SPEC
6044 setTalentPoints(getActiveSpec().getTalentPoints() + talentPoints);
6045#else
6046 m_specs[SPEC_PRIMARY].setTalentPoints(m_specs[SPEC_PRIMARY].getTalentPoints() + talentPoints);
6047 m_specs[SPEC_SECONDARY].setTalentPoints(m_specs[SPEC_SECONDARY].getTalentPoints() + talentPoints);
6048
6049#if VERSION_STRING < Cata
6050 setFreeTalentPoints(getFreeTalentPoints() + talentPoints);
6051#endif
6052#endif
6053 }
6054}
6055
6056void Player::setInitialTalentPoints(bool talentsResetted /*= false*/)
6057{
6058 if (getLevel() < 10)
6059 {
6060 setTalentPoints(0);
6061 return;
6062 }
6063
6064 // Calculate initial talent points based on level
6065 uint32_t talentPoints = 0;
6066#if VERSION_STRING >= Cata
6067 auto talentPointsAtLevel = sNumTalentsAtLevel.lookupEntry(getLevel());
6068 if (talentPointsAtLevel != nullptr)
6069 talentPoints = static_cast<uint32_t>(talentPointsAtLevel->talentPoints);
6070#else
6071 talentPoints = getLevel() - 9;
6072#endif
6073
6074#ifdef FT_DEATH_KNIGHT
6075 if (getClass() == DEATHKNIGHT)
6076 {
6077 if (GetMapId() == 609)
6078 {
6079 // If Death Knight is in the instanced Ebon Hold (map 609), talent points are calculated differently,
6080 // because Death Knights receive their talent points from their starting quest chain.
6081 // However if Death Knight is not in the instanced Ebon Hold, it is safe to assume that
6082 // the player has completed the DK starting quest chain and normal calculation can be used.
6083 uint32_t dkTalentPoints = 0;
6084#if VERSION_STRING >= Cata
6085 auto dkBaseTalentPoints = sNumTalentsAtLevel.lookupEntry(55);
6086 if (dkBaseTalentPoints != nullptr)
6087 dkTalentPoints = getLevel() < 55 ? 0 : talentPoints - static_cast<uint32_t>(dkBaseTalentPoints->talentPoints);
6088#else
6089 dkTalentPoints = getLevel() < 55 ? 0 : getLevel() - 55;
6090#endif
6091 // Add talent points from quests
6092 dkTalentPoints += m_talentPointsFromQuests;
6093
6094 if (dkTalentPoints < talentPoints)
6095 talentPoints = dkTalentPoints;
6096 }
6097
6098 // Add extra talent points if any is set in config files
6099 talentPoints += worldConfig.player.deathKnightStartTalentPoints;
6100 }
6101#endif
6102
6103 // If player's level is increased, player's already spent talent points must be subtracted from initial talent points
6104 uint32_t usedTalentPoints = 0;
6105 if (!talentsResetted)
6106 {
6107#ifdef FT_DUAL_SPEC
6108 if (m_talentSpecsCount == 2)
6109 {
6111 if (m_specs[inactiveSpec].getTalents().size() > 0)
6112 {
6113 uint32_t usedTalentPoints2 = 0;
6114 for (const auto& [talentId, rank] : m_specs[inactiveSpec].getTalents())
6115 {
6116 usedTalentPoints2 += rank + 1;
6117 }
6118
6119 if (usedTalentPoints2 > talentPoints)
6120 usedTalentPoints2 = talentPoints;
6121
6122 m_specs[inactiveSpec].setTalentPoints(talentPoints - usedTalentPoints2);
6123 }
6124 }
6125#endif
6126 if (getActiveSpec().getTalents().size() > 0)
6127 {
6128 for (const auto& [talentId, rank] : getActiveSpec().getTalents())
6129 {
6130 usedTalentPoints += rank + 1;
6131 }
6132
6133 if (usedTalentPoints > talentPoints)
6134 usedTalentPoints = talentPoints;
6135 }
6136 }
6137
6138 setTalentPoints(talentPoints - usedTalentPoints, false);
6139 smsg_TalentsInfo(false);
6140}
6141
6146
6148{
6149 m_talentPointsFromQuests = talentPoints;
6150}
6151
6152void Player::smsg_TalentsInfo([[maybe_unused]]bool SendPetTalents)
6153{
6154 // TODO: classic and tbc
6155#if VERSION_STRING < Mop
6156#if VERSION_STRING >= WotLK
6158 data << uint8_t(SendPetTalents ? 1 : 0);
6159 if (SendPetTalents)
6160 {
6161 if (getPet() != nullptr)
6163 return;
6164 }
6165 else
6166 {
6167 data << uint32_t(getActiveSpec().getTalentPoints()); // Free talent points
6168 data << uint8_t(m_talentSpecsCount); // How many specs player has
6169 data << uint8_t(m_talentActiveSpec); // Which spec is active right now
6170
6173
6174 // Loop through specs
6175 for (uint8_t specId = 0; specId < m_talentSpecsCount; ++specId)
6176 {
6177 PlayerSpec spec = m_specs[specId];
6178
6179#if VERSION_STRING >= Cata
6180 // Send primary talent tree
6182#endif
6183
6184 // How many talents player has learnt
6185 data << uint8_t(spec.getTalents().size());
6186 for (const auto& [talentId, rank] : spec.getTalents())
6187 {
6188 data << uint32_t(talentId);
6189 data << uint8_t(rank);
6190 }
6191
6192 // What kind of glyphs player has
6193 data << uint8_t(GLYPHS_COUNT);
6194 for (uint8_t i = 0; i < GLYPHS_COUNT; ++i)
6195 {
6196 data << uint16_t(getGlyph(specId, i));
6197 }
6198 }
6199 }
6200 getSession()->SendPacket(&data);
6201#endif
6202#else
6204 data << uint8_t(m_talentActiveSpec); // Which spec is active right now
6205 data.writeBits(m_talentSpecsCount, 19);
6206
6207 auto wpos = std::make_unique<size_t[]>(m_talentSpecsCount);
6208 for (int i = 0; i < m_talentSpecsCount; ++i)
6209 {
6210 wpos[i] = data.bitwpos();
6211 data.writeBits(0, 23);
6212 }
6213
6214 data.flushBits();
6215
6216 for (auto specId = 0; specId < m_talentSpecsCount; ++specId)
6217 {
6218 PlayerSpec spec = m_specs[specId];
6219
6220 for (uint8_t i = 0; i < 6; ++i)
6221 data << uint16_t(getGlyph(specId, i));
6222
6223 int32_t talentCount = 0;
6224 for (const auto& [talentId, rank] : spec.getTalents())
6225 {
6226 data << uint16_t(talentId);
6227 talentCount++;
6228 }
6229 data.PutBits(wpos[specId], talentCount, 23);
6230 data << uint32_t(spec.getTalentPoints());
6231 }
6232
6233 getSession()->SendPacket(&data);
6234#endif
6235}
6236
6237void Player::activateTalentSpec([[maybe_unused]]uint8_t specId)
6238{
6239#if VERSION_STRING < Mop
6240#ifndef FT_DUAL_SPEC
6241 return;
6242#else
6243 if (specId >= MAX_SPEC_COUNT || m_talentActiveSpec >= MAX_SPEC_COUNT || m_talentActiveSpec == specId)
6244 return;
6245
6246 // Dismiss current pet or set temporarily unsummoned pet offline
6247 if (getPet() != nullptr)
6248 getPet()->unSummon();
6249 else
6251
6252 // Reset action buttons on client
6253 sendActionBars(2);
6254
6255 // Remove old glyphs
6256 for (uint8_t i = 0; i < GLYPHS_COUNT; ++i)
6257 {
6258 const auto glyphProperties = sGlyphPropertiesStore.lookupEntry(m_specs[m_talentActiveSpec].getGlyph(i));
6259 if (glyphProperties != nullptr)
6260 removeAllAurasById(glyphProperties->SpellID);
6261 }
6262
6263 // Remove old talents and move them to deleted spells
6264 for (const auto& [talentId, rank] : m_specs[m_talentActiveSpec].getTalents())
6265 {
6266 const auto talentInfo = sTalentStore.lookupEntry(talentId);
6267 if (talentInfo != nullptr)
6268 _removeSpell(talentInfo->RankID[rank], true, false, true, true);
6269 }
6270
6271 m_talentActiveSpec = specId;
6272
6273 // Add new glyphs
6274 for (uint8_t i = 0; i < GLYPHS_COUNT; ++i)
6275 {
6276 const auto glyphProperties = sGlyphPropertiesStore.lookupEntry(m_specs[m_talentActiveSpec].getGlyph(i));
6277 if (glyphProperties != nullptr)
6278 castSpell(this, glyphProperties->SpellID, true);
6279 }
6280
6281 // Add new talents
6282 for (const auto& [talentId, rank] : m_specs[m_talentActiveSpec].getTalents())
6283 {
6284 const auto talentInfo = sTalentStore.lookupEntry(talentId);
6285 if (talentInfo == nullptr)
6286 continue;
6287 auto isSingleRankTalent = rank == 0;
6288 if (isSingleRankTalent)
6289 {
6290 for (uint8_t talentRank = 1; talentRank < 5; ++talentRank)
6291 {
6292 if (talentInfo->RankID[talentRank] != 0)
6293 {
6294 isSingleRankTalent = false;
6295 break;
6296 }
6297 }
6298 }
6299 _addSpell(talentInfo->RankID[rank], 0, !isSingleRankTalent);
6300 }
6301
6302 // Set action buttons from new spec
6303 sendActionBars(1);
6304
6305 // Reset power
6306 setPower(getPowerType(), 0);
6307 sendPowerUpdate(false);
6308
6309 // Check offhand
6311
6312 // Send talent points
6314#endif
6315#endif
6316}
6317
6320
6322{
6323 if (resetnum == 0)
6324 return 10000;
6325
6326 if (resetnum > 10)
6327 return 500000;
6328
6329 return resetnum * 50000;
6330}
6331
6332/////////////////////////////////////////////////////////////////////////////////////////
6333// Tutorials
6335{
6336 if (id < 8)
6337 return m_tutorials[id];
6338 return 0;
6339}
6340
6342{
6343 if (id < 8)
6344 {
6345 m_tutorials[id] = value;
6346 m_tutorialsDirty = true;
6347 }
6348}
6349
6351{
6352 if (auto result = CharacterDatabase.Query("SELECT * FROM tutorials WHERE playerId = %u", getGuidLow()))
6353 {
6354 auto* const fields = result->Fetch();
6355 for (uint8_t id = 0; id < 8; ++id)
6356 m_tutorials[id] = fields[id + 1].asUint32();
6357 }
6358 m_tutorialsDirty = false;
6359}
6360
6362{
6363 if (m_tutorialsDirty)
6364 {
6365 CharacterDatabase.Execute("DELETE FROM tutorials WHERE playerid = %u;", getGuidLow());
6366 CharacterDatabase.Execute("INSERT INTO tutorials VALUES('%u','%u','%u','%u','%u','%u','%u','%u','%u');", getGuidLow(), m_tutorials[0], m_tutorials[1], m_tutorials[2], m_tutorials[3], m_tutorials[4], m_tutorials[5], m_tutorials[6], m_tutorials[7]);
6367
6368 m_tutorialsDirty = false;
6369 }
6370}
6371
6372/////////////////////////////////////////////////////////////////////////////////////////
6373// Actionbar
6375{
6376 if (button >= PLAYER_ACTION_BUTTON_COUNT)
6377 return;
6378
6379 getActiveSpec().getActionButton(button).Action = action;
6380 getActiveSpec().getActionButton(button).Misc = misc;
6381 getActiveSpec().getActionButton(button).Type = type;
6382}
6383
6384void Player::sendActionBars([[maybe_unused]]uint8_t action)
6385{
6386#if VERSION_STRING < Mop
6388
6389#if VERSION_STRING == WotLK
6390 data << uint8_t(action);
6391#endif
6392
6393 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6394 {
6395 // TODO: this needs investigation
6396 // action, as in spell id, can be and will be over uint16_t max (65535) on wotlk and cata
6397 // but if I send action in uint32_t, client ignores the button completely and leaves an empty button slot, or corrupts other slots as well
6398 // however casting the action to uint16_t seems to somehow work. I tested it with a spell id over 65535.
6399 // but this is not a solution and can cause undefined behaviour... (previously ActionButton::Action was stored in uint16_t)
6400 // I believe client accepts at most 4 bytes per button -Appled
6401 data << uint16_t(getActiveSpec().getActionButton(i).Action);
6402#if VERSION_STRING < WotLK
6403 data << getActiveSpec().getActionButton(i).Type;
6404 data << getActiveSpec().getActionButton(i).Misc;
6405#else
6406 // Since Wotlk misc needs to be sent before type
6407 data << getActiveSpec().getActionButton(i).Misc;
6408 data << getActiveSpec().getActionButton(i).Type;
6409#endif
6410 }
6411#else
6413
6415
6416 // Bits
6417 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6418 data.writeBit(buttons[i][4]);
6419
6420 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6421 data.writeBit(buttons[i][5]);
6422
6423 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6424 data.writeBit(buttons[i][3]);
6425
6426 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6427 data.writeBit(buttons[i][1]);
6428
6429 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6430 data.writeBit(buttons[i][6]);
6431
6432 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6433 data.writeBit(buttons[i][7]);
6434
6435 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6436 data.writeBit(buttons[i][0]);
6437
6438 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6439 data.writeBit(buttons[i][2]);
6440
6441 // Data
6442 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6443 data.WriteByteSeq(buttons[i][0]);
6444
6445 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6446 data.WriteByteSeq(buttons[i][1]);
6447
6448 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6449 data.WriteByteSeq(buttons[i][4]);
6450
6451 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6452 data.WriteByteSeq(buttons[i][6]);
6453
6454 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6455 data.WriteByteSeq(buttons[i][7]);
6456
6457 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6458 data.WriteByteSeq(buttons[i][2]);
6459
6460 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6461 data.WriteByteSeq(buttons[i][5]);
6462
6463 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
6464 data.WriteByteSeq(buttons[i][3]);
6465#endif
6466
6467#if VERSION_STRING >= Cata
6468 data << uint8_t(action);
6469#endif
6470
6471 getSession()->SendPacket(&data);
6472}
6473
6474//////////////////////////////////////////////////////////////////////////////////////////
6475// Auction
6476void Player::sendAuctionCommandResult(Auction* auction, uint32_t action, uint32_t errorCode, uint32_t bidError)
6477{
6478 const auto auctionId = auction ? auction->Id : 0;
6479
6480#if VERSION_STRING >= Cata
6481 uint64_t outBid = 0;
6482 uint64_t highestBid = 0;
6483#else
6484 uint32_t outBid = 0;
6485 uint32_t highestBid = 0;
6486#endif
6487 uint64_t highestBidderGuid = 0;
6488
6489 if (auction)
6490 {
6491 outBid = auction->highestBid ? auction->getAuctionOutBid() : 0;
6492 highestBid = auction->highestBid;
6493 highestBidderGuid = auction->highestBidderGuid;
6494 }
6495
6496 sendPacket(SmsgAuctionCommandResult(auctionId, action, errorCode, outBid, highestBid, bidError, highestBidderGuid).serialise().get());
6497}
6498
6499//////////////////////////////////////////////////////////////////////////////////////////
6500// Trade
6502{
6503 return m_TradeData != nullptr ? m_TradeData->getTradeTarget() : nullptr;
6504}
6505
6507{
6508 return m_TradeData.get();
6509}
6510
6511void Player::cancelTrade(bool sendToSelfAlso, bool silently /*= false*/)
6512{
6513 // TODO: for some reason client sends multiple trade cancel packets which at some point leads to nullptr trade data
6514 // investigate why client sends so many packets but use mutex for now to prevent crashes -Appled
6515 std::scoped_lock<std::mutex> guard(m_tradeMutex);
6516
6517 if (m_TradeData != nullptr)
6518 {
6519 if (sendToSelfAlso)
6521
6522 if (auto* tradeTarget = m_TradeData->getTradeTarget())
6523 {
6524 std::scoped_lock<std::mutex> targetGuard(tradeTarget->m_tradeMutex);
6525 if (!silently)
6526 tradeTarget->getSession()->sendTradeResult(TRADE_STATUS_CANCELLED);
6527
6528 tradeTarget->m_TradeData = nullptr;
6529 }
6530
6531 m_TradeData = nullptr;
6532 }
6533}
6534
6535//////////////////////////////////////////////////////////////////////////////////////////
6536// Messages
6537void Player::sendReportToGmMessage(std::string playerName, std::string damageLog)
6538{
6539 std::string gm_ann(MSG_COLOR_GREEN);
6540
6541 gm_ann += "|HPlayer:";
6542 gm_ann += playerName;
6543 gm_ann += "|h[";
6544 gm_ann += playerName;
6545 gm_ann += "]|h: ";
6546 gm_ann += MSG_COLOR_YELLOW;
6547 gm_ann += damageLog;
6548
6549 sWorld.sendMessageToOnlineGms(gm_ann);
6550}
6551
6552void Player::broadcastMessage(const char* Format, ...)
6553{
6554 va_list list;
6555 va_start(list, Format);
6556 char Message[1024];
6557 vsnprintf(Message, 1024, Format, list);
6558 va_end(list);
6559
6561}
6562
6563void Player::sendAreaTriggerMessage(const char* message, ...)
6564{
6565 va_list list;
6566 va_start(list, message);
6567 char msg[500];
6568 vsnprintf(msg, 500, message, list);
6569 va_end(list);
6570
6571 m_session->SendPacket(SmsgAreaTriggerMessage(0, msg, 0).serialise().get());
6572}
6573
6574//////////////////////////////////////////////////////////////////////////////////////////
6575// Items
6577{
6579 if (offHandWeapon == nullptr)
6580 return;
6581
6582 auto needToRemove = true;
6583 // Check if player has a two-handed weapon in offhand
6584 if (offHandWeapon->getItemProperties()->InventoryType == INVTYPE_2HWEAPON)
6585 {
6586 needToRemove = !canDualWield2H();
6587 }
6588 else
6589 {
6590 // Player has something in offhand, check if main hand is a two-handed weapon
6591 const auto mainHandWeapon = getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
6592 if (mainHandWeapon != nullptr && mainHandWeapon->getItemProperties()->InventoryType == INVTYPE_2HWEAPON)
6593 needToRemove = !canDualWield2H();
6594 else
6595 {
6596 // Main hand nor offhand is a two-handed weapon, check if player can dual wield one-handed weapons
6597 if (offHandWeapon->isWeapon())
6598 needToRemove = !canDualWield();
6599 else
6600 needToRemove = false; // Offhand is not a weapon
6601 }
6602 }
6603
6604 if (!needToRemove)
6605 return;
6606
6607 // Unequip offhand and find a bag slot for it
6609 auto result = getItemInterface()->FindFreeInventorySlot(offHandWeapon->getItemProperties());
6610 if (!result.Result)
6611 {
6612 // Player has no free slots in inventory, send it by mail
6613 offHandWeapon->removeFromWorld();
6614 offHandWeapon->setOwner(nullptr);
6615 offHandWeapon->saveToDB(INVENTORY_SLOT_NOT_SET, 0, true, nullptr);
6616 sMailSystem.SendAutomatedMessage(MAIL_TYPE_NORMAL, getGuid(), getGuid(), "There were troubles with your item.", "There were troubles storing your item into your inventory.", 0, 0, offHandWeapon->getGuidLow(), MAIL_STATIONERY_GM);
6617 }
6618 else
6619 {
6620 auto [addResult, returnedItem] = getItemInterface()->SafeAddItem(std::move(offHandWeaponHolder), result.ContainerSlot, result.Slot);
6621 if (!addResult)
6622 {
6623 // TODO: if add fails, should item be sent in mail? now it's destroyed
6624 getItemInterface()->AddItemToFreeSlot(std::move(returnedItem));
6625 }
6626 }
6627}
6628
6630{
6631 if (!canDualWield())
6632 return false;
6633
6634 const auto offHandItem = getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
6635 if (offHandItem == nullptr)
6636 return false;
6637
6638 return offHandItem->isWeapon();
6639}
6640
6641bool Player::hasItem(uint32_t itemId, uint32_t amount /*= 1*/, bool checkBankAlso /*= false*/) const
6642{
6643 return getItemInterface()->GetItemCount(itemId, checkBankAlso) >= amount;
6644}
6645
6646#if VERSION_STRING == WotLK
6647void Player::calculateHeirloomBonus(ItemProperties const* proto, int16_t slot, bool apply)
6648{
6649 WDB::Structures::ScalingStatDistributionEntry const* ssd = getScalingStatDistributionFor(*proto);
6650 WDB::Structures::ScalingStatValuesEntry const* ssvrow = getScalingStatValuesFor(*proto);
6651
6652 if (!ssd || !ssvrow)
6653 return;
6654
6655 std::map<uint32_t, int32_t> tempStats;
6656
6657 // Loop through 10 proto stats and try to find matching scaling stats
6658 for (uint32_t id = 0; id < MAX_ITEM_PROTO_STATS; ++id)
6659 {
6660 uint32_t statType = 0;
6661 int32_t val = 0;
6662
6663 if (ssd && ssvrow)
6664 {
6665 if (ssd->stat[id] < 0)
6666 continue;
6667 statType = ssd->stat[id];
6668 val = (ssvrow->getScalingStatDistributionMultiplier(proto->ScalingStatsFlag) * ssd->statmodifier[id]) / 10000;
6669
6670 tempStats[statType] = val;
6671 }
6672 }
6673
6674 // Loop through general stats from db and add all types not found
6675 for (auto generalStats : proto->generalStatsMap)
6676 {
6677 if (tempStats.size() < MAX_ITEM_PROTO_STATS)
6678 {
6679 if (tempStats.find(generalStats.first) == tempStats.end())
6680 tempStats[generalStats.first] = generalStats.second;
6681 }
6682 }
6683
6684 // Loop through all collected stats and apply them
6685 auto it = tempStats.begin();
6686 for (uint32_t id = 0; id < MAX_ITEM_PROTO_STATS; ++id)
6687 {
6688 uint32_t statType = it->first;
6689 int32_t val = it->second;
6690
6691 if (val == 0)
6692 {
6693 ++it;
6694 continue;
6695 }
6696
6697 switch (statType)
6698 {
6699 case ITEM_MOD_MANA:
6700 modifyBonuses(ITEM_MOD_MANA, val, apply);
6701 break;
6702 case ITEM_MOD_HEALTH: // modify HP
6703 modifyBonuses(ITEM_MOD_HEALTH, val, apply);
6704 break;
6705 case ITEM_MOD_AGILITY: // modify agility
6706 modifyBonuses(ITEM_MOD_AGILITY, val, apply);
6707 break;
6708 case ITEM_MOD_STRENGTH: //modify strength
6709 modifyBonuses(ITEM_MOD_STRENGTH, val, apply);
6710 break;
6711 case ITEM_MOD_INTELLECT: //modify intellect
6712 modifyBonuses(ITEM_MOD_INTELLECT, val, apply);
6713 break;
6714 case ITEM_MOD_SPIRIT: //modify spirit
6715 modifyBonuses(ITEM_MOD_SPIRIT, val, apply);
6716 break;
6717 case ITEM_MOD_STAMINA: //modify stamina
6718 modifyBonuses(ITEM_MOD_STAMINA, val, apply);
6719 break;
6722 break;
6725 break;
6728 break;
6731 break;
6734 break;
6737 break;
6740 break;
6743 break;
6746 break;
6749 break;
6752 break;
6755 break;
6758 break;
6761 break;
6764 break;
6767 break;
6770 break;
6773 break;
6776 break;
6779 break;
6782 break;
6785 break;
6788 break;
6791 break;
6794 break;
6797 break;
6800 break;
6803 break;
6806 break;
6809 break;
6812 break;
6815 break;
6818 break;
6821 break;
6822 // deprecated item mods
6827 break;
6828 default:
6829 break;
6830 }
6831
6832 ++it;
6833 }
6834
6835 // Apply Spell Power from ScalingStatValue if set
6836 if (ssvrow)
6837 if (int32_t spellbonus = ssvrow->getSpellBonus(proto->ScalingStatsEntry))
6838 modifyBonuses(ITEM_MOD_SPELL_POWER, spellbonus, apply);
6839
6840 // If set ScalingStatValue armor get it or use item armor
6841 uint32_t armor = proto->Armor;
6842 if (ssvrow)
6843 {
6844 if (uint32_t ssvarmor = ssvrow->getArmorMod(proto->ScalingStatsEntry))
6845 armor = ssvarmor;
6846 }
6847 else if (armor && proto->ArmorDamageModifier)
6848 {
6849 armor -= uint32_t(proto->ArmorDamageModifier);
6850 }
6851
6852 if (armor)
6853 {
6854 if (apply)
6855 m_baseResistance[0] += armor;
6856 else
6857 m_baseResistance[0] -= armor;
6858 }
6859
6860 /* Calculating the damages correct for our level and applying it */
6861 if (ssvrow)
6862 {
6863 for (uint8_t i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
6864 {
6865 float minDamage = proto->Damage[i].Min;
6866 float maxDamage = proto->Damage[i].Max;
6867
6868 // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
6869 if (i == 0) // scaling stats only for first damage
6870 {
6871 int32_t extraDPS = ssvrow->getDPSMod(proto->ScalingStatsFlag);
6872 if (extraDPS)
6873 {
6874 float average = extraDPS * proto->Delay / 1000.0f;
6875 minDamage = 0.7f * average;
6876 maxDamage = 1.3f * average;
6877 }
6878
6880 {
6881 m_baseRangedDamage[0] += apply ? minDamage : -minDamage;
6882 m_baseRangedDamage[1] += apply ? maxDamage : -maxDamage;
6883 }
6884 else
6885 {
6886 if (slot == EQUIPMENT_SLOT_OFFHAND)
6887 {
6888 m_baseOffhandDamage[0] = apply ? minDamage : 0;
6889 m_baseOffhandDamage[1] = apply ? maxDamage : 0;
6890 }
6891 else
6892 {
6893 m_baseDamage[0] = apply ? minDamage : 0;
6894 m_baseDamage[1] = apply ? maxDamage : 0;
6895 }
6896 }
6897 }
6898 }
6899 }
6900}
6901#endif
6902
6903#if VERSION_STRING > WotLK
6904void Player::calculateHeirloomBonus(ItemProperties const* proto, int16_t slot, bool apply)
6905{
6906 // Todo CATA/MOP
6907}
6908#endif
6909
6910#if VERSION_STRING > TBC
6911WDB::Structures::ScalingStatDistributionEntry const* Player::getScalingStatDistributionFor(ItemProperties const& itemProto) const
6912{
6913 if (!itemProto.ScalingStatsEntry)
6914 return nullptr;
6915
6916 return sScalingStatDistributionStore.lookupEntry(itemProto.ScalingStatsEntry);
6917}
6918
6919WDB::Structures::ScalingStatValuesEntry const* Player::getScalingStatValuesFor(ItemProperties const& itemProto) const
6920{
6921 if (!itemProto.ScalingStatsFlag)
6922 return nullptr;
6923
6924 WDB::Structures::ScalingStatDistributionEntry const* ssd = getScalingStatDistributionFor(itemProto);
6925 if (!ssd)
6926 return nullptr;
6927
6928 // req. check at equip, but allow use for extended range if range limit max level, set proper level
6929 uint32_t const ssd_level = std::min(uint32_t(getLevel()), ssd->maxlevel);
6930 return sScalingStatValuesStore.lookupEntry(ssd_level);
6931}
6932#endif
6933
6935{
6936 return m_itemInterface.get();
6937}
6938
6940{
6941 ItemInterface* itemInterface = getItemInterface();
6942
6944 if (Item* item = itemInterface->GetInventoryItem(static_cast<int16_t>(x)))
6945 item->removeAllEnchantments(true);
6946
6948 {
6949 if (Item* item = itemInterface->GetInventoryItem(static_cast<int16_t>(x)))
6950 {
6951 if (item->isContainer())
6952 {
6953 Container* bag = static_cast<Container*>(item);
6954 for (uint32_t ci = 0; ci < bag->getItemProperties()->ContainerSlots; ++ci)
6955 {
6956 if (auto* const bagItem = bag->getItem(static_cast<int16_t>(ci)))
6957 bagItem->removeAllEnchantments(true);
6958 }
6959 }
6960 }
6961 }
6962
6964 if (Item* item = itemInterface->GetInventoryItem(static_cast<int16_t>(x)))
6965 item->removeAllEnchantments(true);
6966}
6967
6968void Player::addGarbageItem(std::unique_ptr<Item> item) { m_GarbageItems.push_back(std::move(item)); }
6969
6971
6972void Player::applyItemMods(Item* item, int16_t slot, bool apply, bool justBrokedown /* = false */, bool skipStatApply /* = false */)
6973{
6974 if (slot >= INVENTORY_SLOT_BAG_END)
6975 return;
6976
6977 if (!item)
6978 return;
6979
6980 ItemProperties const* itemProperties = item->getItemProperties();
6981 if (!itemProperties)
6982 return;
6983
6984 if (!item->isContainer() && !item->getDurability() && item->getMaxDurability() && justBrokedown == false)
6985 return;
6986
6987 item->applyRandomProperties(true);
6988
6989 int32_t setId = 0;
6990 if (itemProperties->ItemSet < 0)
6991 {
6992 if (sMySQLStore.getItemSetLinkedBonus(itemProperties->ItemSet) != 0)
6993 setId = sMySQLStore.getItemSetLinkedBonus(itemProperties->ItemSet);
6994 }
6995 else
6996 {
6997 setId = itemProperties->ItemSet;
6998 }
6999
7000 if (setId != 0)
7001 {
7002 if (auto itemSetEntry = sItemSetStore.lookupEntry(setId))
7003 {
7004 auto itemSetListMember = std::find_if(m_itemSets.begin(), m_itemSets.end(),
7005 [setId](ItemSet const& itemset) { return itemset.setid == setId; });
7006
7007 if (apply)
7008 {
7009 ItemSet* itemSet = nullptr;
7010
7011 // create new itemset if item has itemsetentry but not generated set stats
7012 if (itemSetListMember == m_itemSets.cend())
7013 {
7014 // push to m_itemSets if it was not available before.
7015 auto& newItemSet = m_itemSets.emplace_back(setId, 1);
7016 itemSet = &newItemSet;
7017 }
7018 else
7019 {
7020 itemSet = &(*itemSetListMember);
7021 itemSet->itemscount++;
7022 }
7023
7024 // apply spells from dbc for set
7025 if (!itemSetEntry->RequiredSkillID || (getSkillLineCurrent(static_cast<uint16_t>(itemSetEntry->RequiredSkillID), true) >= itemSetEntry->RequiredSkillAmt))
7026 {
7027 for (uint8_t itemIndex = 0; itemIndex < 8; ++itemIndex)
7028 {
7029 if (itemSet->itemscount == itemSetEntry->itemscount[itemIndex])
7030 {
7031 const auto spellInfo = sSpellMgr.getSpellInfo(itemSetEntry->SpellID[itemIndex]);
7032 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
7033 SpellCastTargets targets(getGuid());
7034 spell->prepare(&targets);
7035 }
7036 }
7037 }
7038 }
7039 else
7040 {
7041 if (itemSetListMember != m_itemSets.cend())
7042 {
7043 auto* itemSet = &(*itemSetListMember);
7044 for (uint8_t itemIndex = 0; itemIndex < 8; ++itemIndex)
7045 if (itemSet->itemscount == itemSetEntry->itemscount[itemIndex])
7046 removeAllAurasByIdForGuid(itemSetEntry->SpellID[itemIndex], getGuid());
7047
7048 if (!(--itemSet->itemscount))
7049 m_itemSets.erase(itemSetListMember);
7050 }
7051 }
7052 }
7053 else
7054 {
7055 sLogger.failure("Item {} has wrong ItemSet {}", itemProperties->ItemId, setId);
7056 }
7057 }
7058
7059 for (auto resistanceStat : itemProperties->resistanceStatsMap)
7060 {
7061 uint8_t spellSchool = SCHOOL_NORMAL;
7062 switch (resistanceStat.first)
7063 {
7065 spellSchool = SCHOOL_HOLY;
7066 break;
7068 spellSchool = SCHOOL_FIRE;
7069 break;
7071 spellSchool = SCHOOL_NATURE;
7072 break;
7074 spellSchool = SCHOOL_FROST;
7075 break;
7077 spellSchool = SCHOOL_SHADOW;
7078 break;
7080 spellSchool = SCHOOL_ARCANE;
7081 break;
7082 default:
7083 continue;
7084 }
7085
7086 if (apply)
7087 m_flatResistanceModifierPos[spellSchool] += resistanceStat.second;
7088 else
7089 m_flatResistanceModifierPos[spellSchool] -= resistanceStat.second;
7090
7091 calcResistance(spellSchool);
7092 }
7093
7094#if VERSION_STRING > TBC
7095 if (itemProperties->ScalingStatsEntry != 0)
7096 {
7097 calculateHeirloomBonus(itemProperties, slot, apply);
7098 }
7099 else
7100#endif
7101 {
7102 // apply general stat mods
7103 for (auto stats : itemProperties->generalStatsMap)
7104 modifyBonuses(stats.first, stats.second, apply);
7105
7106 if (itemProperties->Armor)
7107 {
7108 if (apply)
7109 m_baseResistance[0] += itemProperties->Armor;
7110 else
7111 m_baseResistance[0] -= itemProperties->Armor;
7112 calcResistance(0);
7113 }
7114
7115 if (itemProperties->Damage[0].Min)
7116 {
7117 if (itemProperties->InventoryType == INVTYPE_RANGED || itemProperties->InventoryType == INVTYPE_RANGEDRIGHT || itemProperties->InventoryType == INVTYPE_THROWN)
7118 {
7119 m_baseRangedDamage[0] += apply ? itemProperties->Damage[0].Min : -itemProperties->Damage[0].Min;
7120 m_baseRangedDamage[1] += apply ? itemProperties->Damage[0].Max : -itemProperties->Damage[0].Max;
7121 }
7122 else
7123 {
7124 if (slot == EQUIPMENT_SLOT_OFFHAND)
7125 {
7126 m_baseOffhandDamage[0] = apply ? itemProperties->Damage[0].Min : 0;
7127 m_baseOffhandDamage[1] = apply ? itemProperties->Damage[0].Max : 0;
7128 }
7129 else
7130 {
7131 m_baseDamage[0] = apply ? itemProperties->Damage[0].Min : 0;
7132 m_baseDamage[1] = apply ? itemProperties->Damage[0].Max : 0;
7133 }
7134 }
7135 }
7136 }
7137
7138 if (this->getClass() == DRUID && slot == EQUIPMENT_SLOT_MAINHAND)
7139 {
7140 uint8_t shapeShiftForm = getShapeShiftForm();
7141 if (shapeShiftForm == FORM_MOONKIN || shapeShiftForm == FORM_CAT || shapeShiftForm == FORM_BEAR || shapeShiftForm == FORM_DIREBEAR)
7142 this->applyFeralAttackPower(apply, item);
7143 }
7144
7145 if (apply)
7146 {
7148
7149 for (auto itemSpell : item->getItemProperties()->Spells)
7150 {
7151 if (itemSpell.Id == 0)
7152 continue;
7153
7154 if (auto spellInfo = sSpellMgr.getSpellInfo(itemSpell.Id))
7155 {
7156 if (itemSpell.Trigger == ON_EQUIP)
7157 {
7158 if (spellInfo->getRequiredShapeShift())
7159 {
7160 addShapeShiftSpell(spellInfo->getId());
7161 continue;
7162 }
7163
7164 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
7165 SpellCastTargets targets(getGuid());
7166 spell->castedItemId = item->getEntry();
7167 spell->prepare(&targets);
7168
7169 }
7170 else if (itemSpell.Trigger == CHANCE_ON_HIT)
7171 {
7172 // Calculate proc chance equivalent of 1 PPM
7173 // On average 'chance on hit' effects on items seem to have 1 proc-per-minute
7174 const auto procChance = Util::float2int32((item->getItemProperties()->Delay * 0.001f / 60.0f) * 100.0f);
7175 switch (slot)
7176 {
7177 // 'Chance on hit' in main hand should only proc from main hand hits
7179 addProcTriggerSpell(spellInfo, nullptr, getGuid(), procChance, SpellProcFlags(PROC_ON_DONE_MELEE_HIT | PROC_ON_DONE_MELEE_SPELL_HIT), EXTRA_PROC_ON_MAIN_HAND_HIT_ONLY, nullptr, nullptr, nullptr, this);
7180 break;
7181 // 'Chance on hit' in off hand should only proc from off hand hits
7184 break;
7185 // 'Chance on hit' in ranged slot should only proc from ranged attacks
7187 addProcTriggerSpell(spellInfo, nullptr, getGuid(), procChance, SpellProcFlags(PROC_ON_DONE_RANGED_HIT | PROC_ON_DONE_RANGED_SPELL_HIT), EXTRA_PROC_NULL, nullptr, nullptr, nullptr, this);
7188 break;
7189 // In any other slot, proc on any melee or ranged hit
7190 default:
7192 break;
7193 }
7194 }
7195 }
7196 }
7197 }
7198 else
7199 {
7201 for (auto itemSpell : item->getItemProperties()->Spells)
7202 {
7203 if (itemSpell.Trigger == ON_EQUIP)
7204 {
7205 if (auto spellInfo = sSpellMgr.getSpellInfo(itemSpell.Id))
7206 {
7207 if (spellInfo->getRequiredShapeShift())
7208 removeShapeShiftSpell(spellInfo->getId());
7209 else
7210 removeAllAurasById(itemSpell.Id);
7211 }
7212 }
7213 else if (itemSpell.Trigger == CHANCE_ON_HIT)
7214 {
7215 this->removeProcTriggerSpell(itemSpell.Id);
7216 }
7217 }
7218 }
7219
7220 if (!apply)
7221 {
7222 for (uint16_t posIndex = AuraSlots::POSITIVE_SLOT_START; posIndex < AuraSlots::POSITIVE_SLOT_END; ++posIndex)
7223 {
7224 if (auto* const m_aura = this->getAuraWithAuraSlot(posIndex))
7225 if (m_aura->m_castedItemId && m_aura->m_castedItemId == itemProperties->ItemId)
7226 m_aura->removeAura();
7227 }
7228 }
7229
7230 if (!skipStatApply)
7231 updateStats();
7232}
7233
7234//////////////////////////////////////////////////////////////////////////////////////////
7235// Difficulty
7240
7245
7247{
7248 m_raidDifficulty = diff;
7249}
7250
7255
7256//////////////////////////////////////////////////////////////////////////////////////////
7257// Die, Corpse & Repop
7258void Player::die(Unit* unitAttacker, uint32_t /*damage*/, uint32_t /*spellId*/)
7259{
7260 if (getDeathState() != ALIVE)
7261 return;
7262
7263#ifdef FT_VEHICLES
7264 callExitVehicle();
7265#endif
7266
7267#if VERSION_STRING > TBC
7268 if (unitAttacker != nullptr)
7269 {
7270 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1, 0, 0);
7271 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, GetMapId(), 1, 0);
7272
7273 if (unitAttacker->isPlayer())
7274 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, 0, 0);
7275 else if (unitAttacker->isCreature())
7276 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, 1, 0, 0);
7277 }
7278#endif
7279
7280 if (unitAttacker != nullptr && !sHookInterface.OnPreUnitDie(unitAttacker, this))
7281 return;
7282
7283 if (unitAttacker != nullptr && !unitAttacker->isPlayer())
7285
7287 eventDeath();
7288
7289 if (getChannelObjectGuid() != 0)
7290 {
7291 if (const auto spell = getCurrentSpell(CURRENT_CHANNELED_SPELL))
7292 {
7293 for (uint8_t i = 0; i < 3; i++)
7294 {
7295 if (spell->getSpellInfo()->getEffect(i) == SPELL_EFFECT_PERSISTENT_AREA_AURA)
7296 {
7297 const uint64_t guid = getChannelObjectGuid();
7299 if (!dynamicObject)
7300 continue;
7301
7302 dynamicObject->remove();
7303 }
7304 }
7305
7306 if (spell->getSpellInfo()->getChannelInterruptFlags() == 48140)
7307 interruptSpell(spell->getSpellInfo()->getId());
7308 }
7309 }
7310
7311 for (const auto& inRangePlayer : getInRangePlayersSet())
7312 {
7313 Unit* attacker = dynamic_cast<Unit*>(inRangePlayer);
7314 if (attacker && attacker->isCastingSpell())
7315 {
7316 for (uint8_t i = 0; i < CURRENT_SPELL_MAX; ++i)
7317 {
7318 if (attacker->getCurrentSpell(static_cast<CurrentSpellType>(i)) == nullptr)
7319 continue;
7320
7321 if (attacker->getCurrentSpell(static_cast<CurrentSpellType>(i))->m_targets.getUnitTargetGuid() == getGuid())
7322 attacker->interruptSpellWithSpellType(static_cast<CurrentSpellType>(i));
7323 }
7324 }
7325 }
7326
7327 smsg_AttackStop(unitAttacker);
7329
7331 setDynamicFlags(0);
7332
7333 m_session->SendPacket(SmsgCancelCombat().serialise().get());
7334
7336 data << GetNewGUID();
7337 sendMessageToSet(&data, false);
7338
7339 if (unitAttacker != nullptr && m_WorldMap && m_WorldMap->getScript())
7340 m_WorldMap->getScript()->OnPlayerDeath(this, unitAttacker);
7341
7342 uint32_t selfResSpellId = 0;
7343 if (!m_bg || m_bg && !m_bg->isArena())
7344 {
7345 selfResSpellId = getSelfResurrectSpell();
7346
7347 if (selfResSpellId == 0 && m_reincarnation)
7348 {
7349 SpellInfo const* m_reincarnSpellInfo = sSpellMgr.getSpellInfo(20608);
7350 if (!hasSpellOnCooldown(m_reincarnSpellInfo))
7351 {
7352 uint32_t ankhCount = getItemInterface()->GetItemCount(17030);
7353 if (ankhCount)
7354 selfResSpellId = 21169;
7355 }
7356 }
7357 }
7358
7359 setSelfResurrectSpell(selfResSpellId);
7361
7362 if (unitAttacker != nullptr)
7363 {
7364 if (unitAttacker->IsInWorld() && unitAttacker->isCreature() && static_cast<Creature*>(unitAttacker)->GetScript())
7365 static_cast<Creature*>(unitAttacker)->GetScript()->OnTargetDied(this);
7366
7367 unitAttacker->getAIInterface()->eventOnTargetDied(this);
7368 unitAttacker->smsg_AttackStop(this);
7369 }
7370
7372
7373 m_underwaterTime = 0;
7375
7376 setMoveRoot(true);
7380
7382
7383 // On player death set all pets offline
7384 // If player was i.e. mounted with pet inactive when they died its possible to get pet stuck in weird state
7386
7387 setHealth(0);
7388
7389 //check for spirit of Redemption
7390 if (hasSpell(20711))
7391 {
7392 SpellInfo const* sorInfo = sSpellMgr.getSpellInfo(27827);
7393 if (sorInfo != nullptr)
7394 {
7395 Spell* sor = sSpellMgr.newSpell(this, sorInfo, true, nullptr);
7396 SpellCastTargets targets(getGuid());
7397 sor->prepare(&targets);
7398 }
7399 }
7400
7402
7403 if (getClass() == WARRIOR)
7405#if VERSION_STRING == WotLK
7406 else if (getClass() == DEATHKNIGHT)
7408#endif
7409
7410 if (m_bg)
7411 {
7412 m_bg->HookOnUnitDied(this);
7413 m_bg->HookOnPlayerDeath(this);
7414 }
7415
7416 sHookInterface.OnDeath(this);
7417}
7418
7420{
7421 m_corpseData.location = position;
7422 m_corpseData.instanceId = instanceId;
7423}
7424
7429
7434
7436{
7437 m_isCorpseCreationAllowed = allowed;
7438}
7439
7444
7446{
7447 sObjectMgr.delinkCorpseForPlayer(this);
7448
7450 {
7452 return;
7453 }
7454
7455 const auto corpse = sObjectMgr.createCorpse();
7456 corpse->SetInstanceID(GetInstanceID());
7457 corpse->create(this, GetMapId(), GetPosition());
7458
7459 corpse->setZoneId(getZoneId());
7460
7461 corpse->setRace(getRace());
7462 corpse->setSkinColor(getSkinColor());
7463
7464 corpse->setFace(getFace());
7465 corpse->setHairStyle(getHairStyle());
7466 corpse->setHairColor(getHairColor());
7467 corpse->setFacialFeatures(getFacialFeatures());
7468
7469 corpse->setFlags(CORPSE_FLAG_UNK1);
7470
7471 corpse->setDisplayId(getDisplayId());
7472
7473 if (m_bg)
7474 {
7477
7478 loot.gold = 0;
7479
7480 corpse->generateLoot();
7482 corpse->setDynamicFlags(1);
7483 else
7485
7486 m_lootableOnCorpse = false;
7487 }
7488 else
7489 {
7490 corpse->loot.gold = 0;
7491 }
7492
7493 for (uint8_t slot = 0; slot < EQUIPMENT_SLOT_END; ++slot)
7494 {
7495 if (Item* item = getItemInterface()->GetInventoryItem(slot))
7496 {
7497 const uint32_t displayId = item->getItemProperties()->DisplayInfoID;
7498 const auto inventoryType = static_cast<uint16_t>(item->getItemProperties()->InventoryType);
7499
7500 const uint32_t itemId = static_cast<uint16_t>(displayId) | inventoryType << 24;
7501 corpse->setItem(slot, itemId);
7502 }
7503 }
7504
7505 corpse->saveToDB();
7506}
7507
7509{
7510 if (const auto corpse = sObjectMgr.getCorpseByOwner(this->getGuidLow()))
7511 {
7512 if (!corpse->IsInWorld())
7513 {
7514 if (m_lootableOnCorpse && corpse->getDynamicFlags() != 1)
7515 corpse->setDynamicFlags(1);
7516
7517 if (m_WorldMap == nullptr)
7518 corpse->AddToWorld();
7519 else
7520 corpse->PushToWorld(m_WorldMap);
7521 }
7522
7523 setCorpseData(corpse->GetPosition(), corpse->GetInstanceID());
7524 }
7525 else
7526 {
7527 setCorpseData({ 0, 0, 0, 0 }, 0);
7528 }
7529}
7530
7532{
7533 setCorpseData({ 0, 0, 0, 0 }, 0);
7534
7535 if (const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow()))
7536 {
7537 if (corpse->IsInWorld() && corpse->getCorpseState() == CORPSE_STATE_BODY)
7538 {
7539 corpse->spawnBones();
7540 sObjectMgr.addCorpseDespawnTime(corpse);
7541 }
7542 }
7543}
7544
7546{
7547 sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHECKFORCHEATS);
7548 sEventMgr.RemoveEvents(this, EVENT_PLAYER_FORCED_RESURRECT);
7549
7550 if (m_corpseData.instanceId != 0)
7551 {
7552 if (const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow()))
7553 corpse->resetDeathClock();
7554
7555 resurrect();
7557 return;
7558 }
7559
7560 if (auto transport = this->GetTransport())
7561 {
7562 transport->RemovePassenger(this);
7564
7566 return;
7567 }
7568
7570
7572
7574
7575 const bool hasCorpse = m_bg ? m_bg->CreateCorpse(this) : true;
7576 if (hasCorpse)
7577 createCorpse();
7578
7579 buildRepop();
7580
7581 if (!m_bg || m_bg && m_bg->hasStarted())
7582 {
7583 if (const auto mapInfo = sMySQLStore.getWorldMapInfo(GetMapId()))
7584 {
7585 if (mapInfo->isWorldMap() || mapInfo->isBattlegroundOrArena())
7587 else
7588 repopAtGraveyard(mapInfo->repopx, mapInfo->repopy, mapInfo->repopz, mapInfo->repopmapid);
7589
7590 switch (mapInfo->mapid)
7591 {
7592 case 533: // Naxx
7593 case 550: // The Eye
7594 case 552: // The Arcatraz
7595 case 553: // The Botanica
7596 case 554: // The Mechanar
7597 resurrect();
7598 return;
7599 default:
7600 break;
7601 }
7602 }
7603 else
7604 {
7606 }
7607 }
7608
7609 if (hasCorpse)
7610 {
7612
7613 if (m_corpseData.instanceId != 0)
7614 if (const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow()))
7615 corpse->resetDeathClock();
7616
7619 }
7620}
7621
7622void Player::repopAtGraveyard(float ox, float oy, float oz, uint32_t mapId)
7623{
7624#if VERSION_STRING >= WotLK
7626 return;
7627#endif
7628
7629 bool first = true;
7630
7631 LocationVector currentLocation(ox, oy, oz);
7632 LocationVector finalDestination;
7633 LocationVector temp;
7634
7635 if (!m_bg || !m_bg->HookHandleRepop(this))
7636 {
7637 float closestDistance = 999999.0f;
7638
7639 MySQLStructure::Graveyards const* graveyard = nullptr;
7640 for (const auto& graveyardStore : *sMySQLStore.getGraveyardsStore())
7641 {
7642 graveyard = sMySQLStore.getGraveyard(graveyardStore.second.id);
7643 if (graveyard->mapId == mapId && (graveyard->factionId == getTeam() || graveyard->factionId == 3))
7644 {
7645 temp.ChangeCoords({ graveyard->position_x, graveyard->position_y, graveyard->position_z });
7646 const float distance = currentLocation.distanceSquare(temp);
7647 if (first || distance < closestDistance)
7648 {
7649 first = false;
7650 closestDistance = distance;
7651 finalDestination = temp;
7652 }
7653 }
7654 }
7655
7656 if (first && graveyard)
7657 {
7658 finalDestination.ChangeCoords({ graveyard->position_x, graveyard->position_y, graveyard->position_z });
7659 first = false;
7660 }
7661 }
7662 else
7663 {
7664 return;
7665 }
7666
7667 if (sHookInterface.OnRepop(this) && !first)
7668 safeTeleport(mapId, 0, finalDestination);
7669}
7670
7672{
7673 if (!sHookInterface.OnResurrect(this))
7674 return;
7675
7676 sEventMgr.RemoveEvents(this, EVENT_PLAYER_FORCED_RESURRECT);
7677
7680
7681 if (m_resurrectMana)
7683
7685
7687
7689
7690 uint32_t AuraIds[] = { 20584, 9036, 8326, 55164, 0 };
7691 removeAllAurasById(AuraIds);
7692
7695
7697
7700
7701 m_resurrecter = 0;
7703
7704 for (uint8_t i = 0; i < 7; ++i)
7705 m_schoolImmunityList[i] = 0;
7706
7707 if (m_bg)
7709}
7710
7712{
7713#if VERSION_STRING > TBC
7714 getSession()->SendPacket(SmsgPreResurrect(getGuid()).serialise().get());
7715#endif
7716
7717 uint32_t AuraIds[] = { 20584, 9036, 8326, 0 };
7718 removeAllAurasById(AuraIds);
7719
7720 setHealth(1);
7721
7722 SpellCastTargets target(getGuid());
7723
7724 if (getRace() == RACE_NIGHTELF)
7725 {
7726 SpellInfo const* spellInfo = sSpellMgr.getSpellInfo(9036);
7727 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
7728 spell->prepare(&target);
7729 }
7730 else
7731 {
7732 SpellInfo const* spellInfo = sSpellMgr.getSpellInfo(8326);
7733 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
7734 spell->prepare(&target);
7735 }
7736
7740
7742
7743 setMoveRoot(false);
7745}
7746
7748{
7749 sendPacket(SmsgDurabilityDamageDeath(static_cast<uint32_t>(percent)).serialise().get());
7750
7751 for (uint8_t i = 0; i < EQUIPMENT_SLOT_END; ++i)
7752 {
7753 if (Item* item = getItemInterface()->GetInventoryItem(i))
7754 {
7755 const uint32_t maxDurability = item->getMaxDurability();
7756 const uint32_t durability = item->getDurability();
7757 if (durability)
7758 {
7759 int32_t newDurability = static_cast<uint32_t>(maxDurability * percent);
7760 newDurability = durability - newDurability;
7761 if (newDurability < 0)
7762 newDurability = 0;
7763
7764 if (newDurability <= 0)
7765 applyItemMods(item, i, false, true);
7766
7767 item->setDurability(static_cast<uint32_t>(newDurability));
7768 item->m_isDirty = true;
7769 }
7770 }
7771 }
7772}
7773
7780
7783
7794
7796{
7797 resurrect();
7798
7799 setMoveRoot(false);
7803
7805}
7806
7807//////////////////////////////////////////////////////////////////////////////////////////
7808// Bind
7809void Player::setBindPoint(float x, float y, float z, float o, uint32_t mapId, uint32_t zoneId)
7810{
7811 m_bindData.location = { x, y, z, o };
7812 m_bindData.mapId = mapId;
7813 m_bindData.zoneId = zoneId;
7814}
7815
7819
7820//////////////////////////////////////////////////////////////////////////////////////////
7821// Battleground Entry
7822void Player::setBGEntryPoint(float x, float y, float z, float o, uint32_t mapId, int32_t instanceId)
7823{
7824 m_bgEntryData.location = { x, y, z, o };
7825 m_bgEntryData.mapId = mapId;
7826 m_bgEntryData.instanceId = instanceId;
7827}
7828
7832
7833//////////////////////////////////////////////////////////////////////////////////////////
7834// Charter
7835void Player::unsetCharter(uint8_t charterType) { m_charters[charterType] = nullptr; }
7836Charter const* Player::getCharter(uint8_t charterType) { return m_charters[charterType]; }
7837
7838bool Player::canSignCharter(Charter const* charter, Player* requester)
7839{
7840 if (charter == nullptr || requester == nullptr)
7841 return false;
7842
7843 if (charter->getCharterType() >= CHARTER_TYPE_ARENA_2V2 && getArenaTeam(charter->getCharterType() - 1U) != nullptr)
7844 return false;
7845
7846 if (charter->getCharterType() == CHARTER_TYPE_GUILD && isInGuild())
7847 return false;
7848
7849 if (m_charters[charter->getCharterType()] || requester->getTeam() != getTeam() || this == requester)
7850 return false;
7851
7852 return true;
7853}
7854
7856{
7857 for (uint8_t i = 0; i < NUM_CHARTER_TYPES; ++i)
7858 m_charters[i] = sObjectMgr.getCharterByGuid(getGuid(), static_cast<CharterTypes>(i));
7859}
7860
7861//////////////////////////////////////////////////////////////////////////////////////////
7862// Guild
7865Guild* Player::getGuild() const { return getGuildId() ? sGuildMgr.getGuildById(getGuildId()) : nullptr; }
7866bool Player::isInGuild() { return getGuild() != nullptr; }
7867
7869{
7870 if (auto result = CharacterDatabase.Query("SELECT playerid, guildRank FROM guild_members WHERE playerid = %u", WoWGuid::getGuidLowPartFromUInt64(getGuid())))
7871 {
7872 Field* fields = result->Fetch();
7873 return fields[1].asUint32();
7874 }
7875
7876 return 0;
7877}
7878
7879//////////////////////////////////////////////////////////////////////////////////////////
7880// Group
7884
7886
7889{
7890 if (m_playerInfo->m_Group != nullptr)
7891 {
7893 return true;
7894 }
7895 return false;
7896}
7897
7899
7901
7903{
7904 if (getGroup())
7905 m_groupUpdateFlags = flags;
7906}
7907
7909{
7910 if (getGroup())
7911 m_groupUpdateFlags |= flag;
7912}
7913
7915{
7917 if (isPvpFlagSet())
7918 status |= MEMBER_STATUS_PVP;
7919 if (getDeathState() == CORPSE)
7920 status |= MEMBER_STATUS_DEAD;
7921 else if (isDead())
7922 status |= MEMBER_STATUS_GHOST;
7923 if (isFfaPvpFlagSet())
7924 status |= MEMBER_STATUS_PVP_FFA;
7926 status |= MEMBER_STATUS_AFK;
7928 status |= MEMBER_STATUS_DND;
7929
7930 return status;
7931}
7932
7934{
7936 return;
7937
7938 if (auto group = getGroup())
7939 group->UpdateOutOfRangePlayer(this, true, nullptr);
7940
7942
7943 if (Pet* pet = getPet())
7944 pet->resetAuraUpdateMaskForRaid();
7945}
7946
7952
7955
7957
7958//////////////////////////////////////////////////////////////////////////////////////////
7959// Channels
7961{
7962 if (channel == nullptr)
7963 return;
7964
7965 std::lock_guard<std::mutex> guard(m_mutexChannel);
7966 m_channels.insert(channel);
7967}
7968
7970{
7971 if (channel == nullptr)
7972 return;
7973
7974 std::lock_guard<std::mutex> guard(m_mutexChannel);
7975 m_channels.erase(channel);
7976}
7977
7979{
7981
7982#if VERSION_STRING < WotLK
7983 // TODO: verify if this is needed anymore in < wotlk
7984 // Correct zone for Hall of Legends
7985 if (GetMapId() == 450)
7987 // Correct zone for Champions' Hall
7988 else if (GetMapId() == 449)
7990#endif
7991
7992 // Update only default channels
7993 for (uint8_t i = 0; i < sChatChannelsStore.getNumRows(); ++i)
7994 {
7995 const auto channelDbc = sChatChannelsStore.lookupEntry(i);
7996 if (channelDbc == nullptr)
7997 continue;
7998
7999 Channel* oldChannel = nullptr;
8000
8001 m_mutexChannel.lock();
8002 for (auto _channel : m_channels)
8003 {
8004 if (_channel->getChannelId() == i)
8005 {
8006 // Found same channel
8007 oldChannel = _channel;
8008 break;
8009 }
8010 }
8011 m_mutexChannel.unlock();
8012
8013 if (sChannelMgr.canPlayerJoinDefaultChannel(this, areaEntry, channelDbc))
8014 {
8015 auto channelName = sChannelMgr.generateChannelName(channelDbc, areaEntry);
8016
8017 auto newChannel = sChannelMgr.getOrCreateChannel(channelName, this, channelDbc->id);
8018 if (newChannel == nullptr)
8019 {
8020 // should not happen
8021 sLogger.failure("Player::updateChannels : Could not create new channel {} with name {}", channelDbc->id, channelName);
8022 continue;
8023 }
8024
8025 if (newChannel != oldChannel && !newChannel->hasMember(this))
8026 {
8027 // Join new channel
8028 newChannel->attemptJoin(this, "", true);
8029 // Leave old channel if it exists
8030 if (oldChannel != nullptr)
8031 oldChannel->leaveChannel(this, false);
8032 }
8033 }
8034 else
8035 {
8036 // Leave old channel if it exists
8037 if (oldChannel != nullptr)
8038 oldChannel->leaveChannel(this);
8039 }
8040 }
8041}
8042
8044{
8045 std::set<Channel*> removeList;
8046 m_mutexChannel.lock();
8047
8048 for (const auto& channel : m_channels)
8049 removeList.insert(channel);
8050
8051 m_mutexChannel.unlock();
8052
8053 auto itr = removeList.begin();
8054 while (itr != removeList.end())
8055 {
8056 (*itr)->leaveChannel(this);
8057 itr = removeList.erase(itr);
8058 }
8059}
8060
8061//////////////////////////////////////////////////////////////////////////////////////////
8062// ArenaTeam
8064{
8065 m_arenaTeams[type] = arenaTeam;
8066
8067 if (arenaTeam)
8068 getSession()->SystemMessage("You are now a member of the arena team'%s'.", arenaTeam->m_name.c_str());
8069}
8071
8072bool Player::isInArenaTeam(uint8_t type) const { return m_arenaTeams[type] != nullptr; }
8074{
8075 for (uint8_t i = 0; i < NUM_ARENA_TEAM_TYPES; ++i)
8076 {
8077 m_arenaTeams[i] = sObjectMgr.getArenaTeamByGuid(getGuidLow(), i);
8078 if (m_arenaTeams[i] != nullptr)
8079 {
8080#if VERSION_STRING != Classic
8081 setArenaTeamId(i, m_arenaTeams[i]->m_id);
8082
8083 if (m_arenaTeams[i]->m_leader == getGuidLow())
8084 setArenaTeamMemberRank(i, 0);
8085 else
8086 setArenaTeamMemberRank(i, 1);
8087#endif
8088 }
8089 }
8090}
8091
8092void Player::addArenaPoints(uint32_t arenaPoints, bool sendUpdate)
8093{
8094 this->m_arenaPoints += arenaPoints;
8095 if (this->m_arenaPoints > worldConfig.limit.maxArenaPoints)
8096 this->m_arenaPoints = worldConfig.limit.maxArenaPoints;
8097
8098 if (sendUpdate)
8099 this->updateArenaPoints();
8100}
8101
8103
8104void Player::removeArenaPoints(uint32_t arenaPoints, bool sendUpdate)
8105{
8106 int32_t newPoints = this->m_arenaPoints;
8107 newPoints -= arenaPoints;
8108 if (newPoints < 0)
8109 newPoints = 0;
8110
8111 this->m_arenaPoints = newPoints;
8112
8113 if (sendUpdate)
8114 this->updateArenaPoints();
8115}
8116
8118{
8119#if VERSION_STRING > Classic
8120#if VERSION_STRING < Cata
8121 this->setArenaCurrency(this->m_arenaPoints);
8122#endif
8123#endif
8124
8125 this->updateKnownCurrencies(43307, true);
8126}
8127
8130
8131//////////////////////////////////////////////////////////////////////////////////////////
8132// Honor
8133void Player::addHonor(uint32_t honorPoints, bool sendUpdate)
8134{
8135 if (this->GetMapId() == 559 || this->GetMapId() == 562 || this->GetMapId() == 572)
8136 return;
8137
8138 this->m_honorPoints += honorPoints;
8139 this->m_honorToday += honorPoints;
8140 if (this->m_honorPoints > worldConfig.limit.maxHonorPoints)
8141 this->m_honorPoints = worldConfig.limit.maxHonorPoints;
8142
8143 if (sendUpdate)
8144 this->updateHonor();
8145}
8146
8148
8149void Player::removeHonor(uint32_t honorPoints, bool sendUpdate)
8150{
8151 int32_t newPoints = this->m_honorPoints;
8152 newPoints -= honorPoints;
8153 if (newPoints < 0)
8154 newPoints = 0;
8155
8156 this->m_honorPoints = newPoints;
8157
8158 if (sendUpdate)
8159 this->updateHonor();
8160}
8161
8163{
8164#if VERSION_STRING != Classic
8165 this->setFieldKills((this->m_killsToday | this->m_killsYesterday << 16));
8166#if VERSION_STRING < Cata
8167 this->setContributionToday(this->m_honorToday);
8168 this->setContributionYesterday(this->m_honorYesterday);
8169
8170 this->setHonorCurrency(this->m_honorPoints);
8171#endif
8172#endif
8174
8175 this->updateKnownCurrencies(43308, true);
8176}
8177
8179{
8180 uint32_t current_val = (g_localTime.tm_year << 16) | g_localTime.tm_yday;
8181 if (current_val != m_honorRolloverTime)
8182 {
8183 m_honorRolloverTime = current_val;
8187 }
8188}
8189
8195
8197{
8198 if (count)
8199 {
8200 m_killsToday += count;
8201 m_killsLifetime += count;
8202 return;
8203 }
8204
8205 m_killsToday++;
8207}
8208
8212
8213//////////////////////////////////////////////////////////////////////////////////////////
8214// PvP
8217
8219{
8221
8222 const auto areaTableEntry = this->GetArea();
8223
8224 if (areaTableEntry != nullptr && isAlive() &&
8225 (areaTableEntry->team == AREAC_CONTESTED ||
8226 (isTeamAlliance() && areaTableEntry->team == AREAC_HORDE_TERRITORY) ||
8227 (isTeamHorde() && areaTableEntry->team == AREAC_ALLIANCE_TERRITORY)))
8229}
8230
8232{
8233 auto areaTableEntry = this->GetArea();
8234 if (areaTableEntry == nullptr)
8235 return;
8236
8238 {
8239 if (isPvpFlagSet())
8240 removePvpFlag();
8241 else
8242 stopPvPTimer();
8243
8245 return;
8246 }
8247
8248 if ((areaTableEntry->team == AREAC_ALLIANCE_TERRITORY && isTeamAlliance()) || (areaTableEntry->team == AREAC_HORDE_TERRITORY && isTeamHorde()))
8249 {
8251 resetPvPTimer();
8252 }
8253 else
8254 {
8255 if (areaTableEntry->flags & AREA_CITY_AREA || areaTableEntry->flags & AREA_CITY)
8256 {
8257 if ((areaTableEntry->team == AREAC_ALLIANCE_TERRITORY && isTeamHorde()) || (areaTableEntry->team == AREAC_HORDE_TERRITORY && isTeamAlliance()))
8258 {
8259 if (!isPvpFlagSet())
8260 setPvpFlag();
8261 else
8262 stopPvPTimer();
8263 return;
8264 }
8265 }
8266
8267 if (areaTableEntry->zone)
8268 {
8269 if (auto at2 = AreaStorage::GetAreaById(areaTableEntry->zone))
8270 {
8271 if ((at2->team == AREAC_ALLIANCE_TERRITORY && isTeamAlliance()) || (at2->team == AREAC_HORDE_TERRITORY && isTeamHorde()))
8272 {
8274 resetPvPTimer();
8275
8276 return;
8277 }
8278
8279 if (at2->flags & AREA_CITY_AREA || at2->flags & AREA_CITY)
8280 {
8281 if ((at2->team == AREAC_ALLIANCE_TERRITORY && isTeamHorde()) || (at2->team == AREAC_HORDE_TERRITORY && isTeamAlliance()))
8282 {
8283 if (!isPvpFlagSet())
8284 setPvpFlag();
8285 else
8286 stopPvPTimer();
8287 return;
8288 }
8289 }
8290 }
8291 }
8292
8293 if (areaTableEntry->team == AREAC_SANCTUARY || areaTableEntry->flags & AREA_SANCTUARY)
8294 {
8295 if (isPvpFlagSet())
8296 removePvpFlag();
8297 else
8298 stopPvPTimer();
8299
8302 }
8303 else
8304 {
8306
8307 if (sLogonCommHandler.getRealmType() == REALMTYPE_PVP || sLogonCommHandler.getRealmType() == REALMTYPE_RPPVP)
8308 {
8309 if (!isPvpFlagSet())
8310 setPvpFlag();
8311 else
8312 stopPvPTimer();
8313 }
8314
8315 if (sLogonCommHandler.getRealmType() == REALMTYPE_NORMAL || sLogonCommHandler.getRealmType() == REALMTYPE_RP)
8316 {
8318 {
8319 if (!isPvpFlagSet())
8320 setPvpFlag();
8321 }
8323 {
8324 resetPvPTimer();
8325 }
8326 }
8327
8328 if (areaTableEntry->flags & AREA_PVP_ARENA)
8329 {
8330 if (!isPvpFlagSet())
8331 setPvpFlag();
8332
8333 setFfaPvpFlag();
8334 }
8335 else
8336 {
8338 }
8339 }
8340 }
8341}
8342
8344{
8345 if (sLogonCommHandler.getRealmType() == REALMTYPE_NORMAL || sLogonCommHandler.getRealmType() == REALMTYPE_RP)
8346 {
8347 if (m_pvpTimer > 0)
8348 {
8349 stopPvPTimer();
8350
8352#if VERSION_STRING >= WotLK
8353 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8354#endif
8355
8356 if (!isPvpFlagSet())
8357 setPvpFlag();
8358 }
8359 else
8360 {
8361 if (isPvpFlagSet())
8362 {
8363 auto areaTableEntry = this->GetArea();
8364 if (areaTableEntry && (areaTableEntry->flags & AREA_CITY_AREA || areaTableEntry->flags & AREA_CITY))
8365 {
8366 if ((areaTableEntry->team == AREAC_ALLIANCE_TERRITORY && isTeamHorde()) || (areaTableEntry->team == AREAC_HORDE_TERRITORY && isTeamAlliance()))
8367 {
8368 }
8369 else
8370 {
8371 resetPvPTimer();
8372 }
8373 }
8374 else
8375 {
8376 resetPvPTimer();
8377 }
8378
8380#if VERSION_STRING >= WotLK
8381 addPlayerFlags(PLAYER_FLAG_PVP_TIMER);
8382#endif
8383 }
8384 else
8385 {
8387#if VERSION_STRING >= WotLK
8388 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8389#endif
8390
8391 stopPvPTimer();
8392 setPvpFlag();
8393 }
8394 }
8395 }
8396 else if (sLogonCommHandler.getRealmType() == REALMTYPE_PVP || sLogonCommHandler.getRealmType() == REALMTYPE_RPPVP)
8397 {
8398 auto at = this->GetArea();
8399 if (at == nullptr)
8400 return;
8401
8402 // This is where all the magic happens :P
8403 if ((at->team == AREAC_ALLIANCE_TERRITORY && isTeamAlliance()) || (at->team == AREAC_HORDE_TERRITORY && isTeamHorde()))
8404 {
8405 if (m_pvpTimer > 0)
8406 {
8407 // Means that we typed /pvp while we were "cooling down". Stop the timer.
8408 stopPvPTimer();
8409
8411#if VERSION_STRING >= WotLK
8412 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8413#endif
8414
8415 if (!isPvpFlagSet())
8416 setPvpFlag();
8417 }
8418 else
8419 {
8420 if (isPvpFlagSet())
8421 {
8422 // Start the "cooldown" timer.
8423 resetPvPTimer();
8424
8426#if VERSION_STRING >= WotLK
8427 addPlayerFlags(PLAYER_FLAG_PVP_TIMER);
8428#endif
8429 }
8430 else
8431 {
8432 // Move into PvP state.
8434#if VERSION_STRING >= WotLK
8435 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8436#endif
8437
8438 stopPvPTimer();
8439 setPvpFlag();
8440 }
8441 }
8442 }
8443 else
8444 {
8445 if (at->zone)
8446 {
8448 if (at2 && ((at2->team == AREAC_ALLIANCE_TERRITORY && isTeamAlliance()) || (at2->team == AREAC_HORDE_TERRITORY && isTeamHorde())))
8449 {
8450 if (m_pvpTimer > 0)
8451 {
8452 // Means that we typed /pvp while we were "cooling down". Stop the timer.
8453 stopPvPTimer();
8454
8456#if VERSION_STRING >= WotLK
8457 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8458#endif
8459
8460 if (!isPvpFlagSet())
8461 setPvpFlag();
8462 }
8463 else
8464 {
8465 if (isPvpFlagSet())
8466 {
8467 // Start the "cooldown" timer.
8468 resetPvPTimer();
8469
8471#if VERSION_STRING >= WotLK
8472 addPlayerFlags(PLAYER_FLAG_PVP_TIMER);
8473#endif
8474 }
8475 else
8476 {
8477 // Move into PvP state.
8479#if VERSION_STRING >= WotLK
8480 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8481#endif
8482
8483 stopPvPTimer();
8484 setPvpFlag();
8485 }
8486 }
8487 return;
8488 }
8489 }
8490
8492 {
8494#if VERSION_STRING >= WotLK
8495 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
8496#endif
8497 }
8498 else
8499 {
8501#if VERSION_STRING >= WotLK
8502 addPlayerFlags(PLAYER_FLAG_PVP_TIMER);
8503#endif
8504 }
8505 }
8506 }
8507}
8508
8510{
8511 this->updateHonor();
8512 this->updateArenaPoints();
8513}
8514
8516{
8517#if VERSION_STRING > Classic
8518 const auto index = static_cast<uint8_t>(title / 32);
8519
8520 return (getKnownTitles(index) & 1ULL << static_cast<uint64_t>((title % 32))) != 0;
8521#else
8522 return false;
8523#endif
8524}
8525
8527{
8528#if VERSION_STRING > Classic
8529 if (!set && !hasPvPTitle(title))
8530 return;
8531
8532 const auto index = static_cast<uint8_t>(title / 32);
8533 const uint64_t current = getKnownTitles(index);
8534
8535 if (set)
8536 setKnownTitles(index, current | 1ULL << static_cast<uint64_t>((title % 32)));
8537 else
8538 setKnownTitles(index, current & ~1 << (title % 32));
8539
8540 m_session->SendPacket(SmsgTitleEarned(title, set ? 1 : 0).serialise().get());
8541#endif
8542}
8543
8544//////////////////////////////////////////////////////////////////////////////////////////
8545// Battleground
8548
8551
8554
8558
8559bool Player::isQueuedForRbg() const { return this->m_isQueuedForRbg; }
8561
8570
8571bool Player::hasWonRbgToday() const { return this->m_hasWonRbgToday; }
8573
8576
8577bool Player::hasBgFlag() const { return m_bgHasFlag; }
8579
8580void Player::setRoles(uint8_t role) { m_roles = role; }
8582
8583void Player::fillRandomBattlegroundReward(bool wonBattleground, uint32_t& honorPoints, uint32_t& arenaPoints)
8584{
8585 auto honorForSingleKill = HonorHandler::CalculateHonorPointsForKill(this->getLevel(), this->getLevel());
8586
8587 if (wonBattleground)
8588 {
8589 if (this->m_hasWonRbgToday)
8590 {
8591 honorPoints = worldConfig.bg.honorableKillsRbg * honorForSingleKill;
8592 arenaPoints = worldConfig.bg.honorableArenaWinRbg;
8593 }
8594 else
8595 {
8596 honorPoints = worldConfig.bg.firstRbgHonorValueToday * honorForSingleKill;
8597 arenaPoints = worldConfig.bg.firstRbgArenaHonorValueToday;
8598 }
8599 }
8600 else
8601 {
8602 honorPoints = worldConfig.bg.honorByLosingRbg * honorForSingleKill;
8603 arenaPoints = worldConfig.bg.honorByLosingArenaRbg;
8604 }
8605}
8606
8608{
8609 uint32_t honorPoints, arenaPoints;
8610 this->fillRandomBattlegroundReward(wonBattleground, honorPoints, arenaPoints);
8611 this->addHonor(honorPoints, false);
8612 this->addArenaPoints(arenaPoints, false);
8613 this->updatePvPCurrencies();
8614}
8615
8617{
8618 uint32_t level = getLevel();
8619
8620 if (level < 10)
8621 return 0;
8622 if (level < 20)
8623 return 1;
8624 if (level < 30)
8625 return 2;
8626 if (level < 40)
8627 return 3;
8628 if (level < 50)
8629 return 4;
8630 if (level < 60)
8631 return 5;
8632 if (level < 70)
8633 return 6;
8634 if (level < 80)
8635 return 7;
8636
8637 return 8;
8638}
8639
8640//////////////////////////////////////////////////////////////////////////////////////////
8641// Quests
8643{
8644 bool bValid = false;
8645 bool hasquest = true;
8646 bool bSkipLevelCheck = false;
8647
8648 QuestProperties const* questProperties = nullptr;
8649
8650 Object* qst_giver = nullptr;
8651
8652 WoWGuid wowGuid;
8653 wowGuid.Init(guid);
8654
8655 if (wowGuid.isUnit())
8656 {
8657 Creature* quest_giver = m_WorldMap->getCreature(wowGuid.getGuidLowPart());
8658 if (quest_giver)
8659 qst_giver = quest_giver;
8660 else
8661 return;
8662
8663 hasquest = quest_giver->HasQuest(quest_id, 1);
8664 if (quest_giver->isQuestGiver())
8665 {
8666 bValid = true;
8667 questProperties = sMySQLStore.getQuestProperties(quest_id);
8668 }
8669 }
8670 else if (wowGuid.isGameObject())
8671 {
8672 GameObject* quest_giver = m_WorldMap->getGameObject(wowGuid.getGuidLowPart());
8673 if (quest_giver)
8674 qst_giver = quest_giver;
8675 else
8676 return;
8677
8678 bValid = true;
8679 questProperties = sMySQLStore.getQuestProperties(quest_id);
8680 }
8681 else if (wowGuid.isItem())
8682 {
8683 Item* quest_giver = getItemInterface()->GetItemByGUID(guid);
8684 if (quest_giver)
8685 qst_giver = quest_giver;
8686 else
8687 return;
8688
8689 bValid = true;
8690 bSkipLevelCheck = true;
8691 questProperties = sMySQLStore.getQuestProperties(quest_id);
8692 }
8693 else if (wowGuid.isPlayer())
8694 {
8695 Player* quest_giver = m_WorldMap->getPlayer(static_cast<uint32_t>(guid));
8696 if (quest_giver)
8697 qst_giver = quest_giver;
8698 else
8699 return;
8700
8701 bValid = true;
8702 questProperties = sMySQLStore.getQuestProperties(quest_id);
8703 }
8704
8705 if (!qst_giver)
8706 {
8707 sLogger.debug("WORLD: Invalid questgiver GUID.");
8708 return;
8709 }
8710
8711 if (!bValid || questProperties == nullptr)
8712 {
8713 sLogger.debug("WORLD: Creature is not a questgiver.");
8714 return;
8715 }
8716
8717 if (hasQuestInQuestLog(questProperties->id))
8718 return;
8719
8720 if (qst_giver->isCreature() && dynamic_cast<Creature*>(qst_giver)->m_escorter != nullptr)
8721 {
8722 m_session->SystemMessage("You cannot accept this quest at this time.");
8723 return;
8724 }
8725
8726 // Check the player hasn't already taken this quest, or it isn't available.
8727 const uint32_t status = sQuestMgr.CalcQuestStatus(qst_giver, this, questProperties, 3, bSkipLevelCheck);
8728
8729 if ((!sQuestMgr.IsQuestRepeatable(questProperties) && hasQuestFinished(questProperties->id))
8730 || (status != QuestStatus::Available && status != QuestStatus::Repeatable && status != QuestStatus::AvailableChat)
8731 || !hasquest)
8732 {
8733 return;
8734 }
8735
8736 const uint8_t log_slot = getFreeQuestSlot();
8737 if (log_slot > MAX_QUEST_SLOT)
8738 {
8739 sQuestMgr.SendQuestLogFull(this);
8740 return;
8741 }
8742
8743 if ((questProperties->time != 0) && hasTimedQuestInQuestSlot())
8744 {
8745 sQuestMgr.SendQuestInvalid(INVALID_REASON_HAVE_TIMED_QUEST, this);
8746 return;
8747 }
8748
8749 if (questProperties->count_receiveitems || questProperties->srcitem)
8750 {
8751 const uint32_t slots_required = questProperties->count_receiveitems;
8752
8753 if (getItemInterface()->CalculateFreeSlots(nullptr) < slots_required)
8754 {
8756 sQuestMgr.SendQuestFailed(FAILED_REASON_INV_FULL, questProperties, this);
8757 return;
8758 }
8759 }
8760
8761 auto* questLogEntry = createQuestLogInSlot(questProperties, log_slot);
8762 questLogEntry->updatePlayerFields();
8763
8764 // If the quest should give any items on begin, give them the items.
8765 for (uint32_t receive_item : questProperties->receive_items)
8766 {
8767 if (receive_item)
8768 {
8769 if (auto itemHolder = sObjectMgr.createItem(receive_item, this))
8770 {
8771 auto* item = itemHolder.get();
8772 const auto [addResult, _] = getItemInterface()->AddItemToFreeSlot(std::move(itemHolder));
8773 if (addResult == ADD_ITEM_RESULT_OK)
8774 {
8775 sendItemPushResultPacket(false, true, false,
8776 getItemInterface()->LastSearchItemBagSlot(), getItemInterface()->LastSearchItemSlot(),
8777 1, item->getEntry(), item->getPropertySeed(), item->getRandomPropertiesId(), item->getStackCount());
8778 }
8779 }
8780 }
8781 }
8782
8783 if (questProperties->srcitem && questProperties->srcitem != questProperties->receive_items[0])
8784 {
8785 if (!qst_giver->isItem() || (qst_giver->getEntry() != questProperties->srcitem))
8786 {
8787 if (auto item = sObjectMgr.createItem(questProperties->srcitem, this))
8788 {
8789 item->setStackCount(questProperties->srcitemcount ? questProperties->srcitemcount : 1);
8790 getItemInterface()->AddItemToFreeSlot(std::move(item));
8791 }
8792 }
8793 }
8794
8796
8797 const SpellAreaForQuestMapBounds saBounds = { sSpellMgr.mSpellAreaForQuestMap.lower_bound(quest_id), sSpellMgr.mSpellAreaForQuestMap.upper_bound(quest_id) };
8798 if (saBounds.first != saBounds.second)
8799 {
8800 for (auto itr = saBounds.first; itr != saBounds.second; ++itr)
8801 {
8802 if (itr->second->autoCast && itr->second->fitsToRequirements(this, getZoneId(), getAreaId()))
8803 if (!hasAurasWithId(itr->second->spellId))
8804 castSpell(this, itr->second->spellId, true);
8805 }
8806 }
8807
8808 sQuestMgr.OnQuestAccepted(this, questProperties, qst_giver);
8809
8810 // Hook to Creature Script
8811 if (qst_giver->ToCreature() && qst_giver->ToCreature()->GetScript())
8812 qst_giver->ToCreature()->GetScript()->onQuestAccept(this, questProperties);
8813
8814 sLogger.debug("WORLD: Added new QLE.");
8815 sHookInterface.OnQuestAccept(this, questProperties, qst_giver);
8816}
8817
8819{
8820 if (slotId >= MAX_QUEST_LOG_SIZE)
8821 return nullptr;
8822
8823 if (questProperties == nullptr)
8824 {
8825 m_questlog[slotId] = nullptr;
8826 return nullptr;
8827 }
8828
8829 m_questlog[slotId] = std::make_unique<QuestLogEntry>(questProperties, this, slotId);
8830 return m_questlog[slotId].get();
8831}
8832
8834{
8835 for (auto& questlogSlot : m_questlog)
8836 if (questlogSlot != nullptr)
8837 return true;
8838
8839 return false;
8840}
8841
8843{
8844 if (getQuestLogByQuestId(questId))
8845 return true;
8846
8847 return false;
8848}
8849
8851{
8852 for (uint8_t slotId = 0; slotId < MAX_QUEST_LOG_SIZE; ++slotId)
8853 if (m_questlog[slotId] == nullptr)
8854 return slotId;
8855
8856 return MAX_QUEST_LOG_SIZE + 1;
8857}
8858
8860{
8861 for (auto& questlogSlot : m_questlog)
8862 if (questlogSlot != nullptr)
8863 if (questlogSlot->getQuestProperties()->id == questId)
8864 return questlogSlot.get();
8865
8866 return nullptr;
8867}
8868
8870{
8871 if (slotId < MAX_QUEST_LOG_SIZE)
8872 return m_questlog[slotId].get();
8873
8874 return nullptr;
8875}
8876
8878{
8879 std::lock_guard<std::mutex> lock(m_mutextDailies);
8880 m_finishedDailies.insert(questId);
8881}
8882std::set<uint32_t> Player::getFinishedDailies() const
8883{
8884 std::lock_guard<std::mutex> lock(m_mutextDailies);
8885 return m_finishedDailies;
8886}
8888{
8889 std::lock_guard<std::mutex> lock(m_mutextDailies);
8890 return m_finishedDailies.find(questId) != m_finishedDailies.end();
8891}
8893{
8894 std::lock_guard<std::mutex> lock(m_mutextDailies);
8895 m_finishedDailies.clear();
8896}
8897
8899{
8900 for (auto& questlogSlot : m_questlog)
8901 if (questlogSlot != nullptr && questlogSlot->getQuestProperties()->time != 0)
8902 return true;
8903
8904 return false;
8905}
8906
8908{
8909 if (QuestLogEntry* questLogEntry = this->getQuestLogByQuestId(questId))
8910 {
8911 QuestProperties const* qst = questLogEntry->getQuestProperties();
8912
8913 sQuestMgr.SendQuestUpdateFailedTimer(qst, this);
8914
8915 if (const auto questScript = questLogEntry->getQuestScript())
8916 questScript->OnQuestCancel(this);
8917
8918 questLogEntry->sendQuestFailed(true);
8919 }
8920}
8921
8924
8925void Player::addQuestToRemove(uint32_t questId) { m_removequests.insert(questId); }
8926
8928{
8929 if (m_finishedQuests.find(questId) != m_finishedQuests.end())
8930 return;
8931
8932 m_finishedQuests.insert(questId);
8933}
8934
8936{
8937 return m_finishedQuests.find(questId) != m_finishedQuests.cend();
8938}
8939
8941{
8942 sQuestMgr.AreaExplored(this, questId);
8943}
8944
8946{
8947 m_finishedQuests.erase(questId);
8948 m_finishedDailies.erase(questId);
8949}
8950
8952{
8953 for (const auto& questLogEntry : m_questlog)
8954 {
8955 if (questLogEntry != nullptr)
8956 {
8957 QuestProperties const* questProperties = questLogEntry->getQuestProperties();
8958
8959 // Check the item_quest_association table for an entry related to this item
8960 if (const auto* tempList = sQuestMgr.GetQuestAssociationListForItemId(itemId))
8961 {
8962 for (auto questAssiciation = tempList->cbegin(); questAssiciation != tempList->cend(); ++questAssiciation)
8963 if ((*questAssiciation)->qst == questProperties && (getItemInterface()->GetItemCount(itemId) < (*questAssiciation)->item_count))
8964 return true;
8965 }
8966
8967 // No item_quest association found, check the quest requirements
8968 if (!questProperties->count_required_item)
8969 continue;
8970
8971 for (uint8_t j = 0; j < MAX_REQUIRED_QUEST_ITEM; ++j)
8972 if (questProperties->required_item[j] == itemId && getItemInterface()->GetItemCount(itemId) < questProperties->required_itemcount[j])
8973 return true;
8974 }
8975 }
8976 return false;
8977}
8978
8979void Player::addQuestSpell(uint32_t spellId) { quest_spells.insert(spellId); }
8980
8981//Only for Cast Quests
8983{
8984 if (!quest_spells.empty() && quest_spells.find(spellId) != quest_spells.end())
8985 return true;
8986
8987 return false;
8988}
8989
8990//Only for Cast Quests
8992{
8993 if (!quest_spells.empty())
8994 quest_spells.erase(spellId);
8995}
8996
8997void Player::addQuestMob(uint32_t entry) { quest_mobs.insert(entry); }
8998
8999//Only for Kill Quests
9001{
9002 if (!quest_mobs.empty() && quest_mobs.find(entry) != quest_mobs.end())
9003 return true;
9004
9005 return false;
9006}
9007
9008//Only for Kill Quests
9010{
9011 if (!quest_mobs.empty())
9012 quest_mobs.erase(entry);
9013}
9014
9016{
9017 if (!hasQuestInQuestLog(questId))
9018 return;
9019
9020 if (delay)
9021 {
9022 sEventMgr.AddEvent(this, &Player::addQuestKill, questId, reqId, static_cast<uint32_t>(0), EVENT_PLAYER_UPDATE, delay, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
9023 return;
9024 }
9025
9026 if (QuestLogEntry* questLogEntry = getQuestLogByQuestId(questId))
9027 {
9028 if (QuestProperties const* quest = questLogEntry->getQuestProperties())
9029 {
9030 if (questLogEntry->getMobCountByIndex(reqId) >= quest->required_mob_or_go_count[reqId])
9031 return;
9032
9033 questLogEntry->incrementMobCountForIndex(reqId);
9034 questLogEntry->sendUpdateAddKill(reqId);
9035 questLogEntry->updatePlayerFields();
9036
9037 if (questLogEntry->canBeFinished())
9038 questLogEntry->sendQuestComplete();
9039 }
9040 }
9041}
9042
9044{
9045 for (const auto& itr : getInRangeObjectsSet())
9046 {
9047 auto* obj = itr;
9048 if (obj == nullptr || !obj->isGameObject() || obj->isTransporter())
9049 continue;
9050
9051 if (const auto gameobject = dynamic_cast<GameObject*>(obj))
9052 {
9053 const auto gobProperties = gameobject->GetGameObjectProperties();
9054
9055 // Update dynamic flags for gameobjects with quests or item loot
9056 if (gameobject->isQuestGiver() || !gobProperties->itemMap.empty() || !gobProperties->goMap.empty())
9057 {
9058#if VERSION_STRING < Mop
9059 gameobject->forceBuildUpdateValueForField(getOffsetForStructuredField(WoWGameObject, dynamic), this);
9060#else
9061 gameobject->forceBuildUpdateValueForField(getOffsetForStructuredField(WoWObject, dynamic_field), this);
9062#endif
9063 }
9064 }
9065 }
9066}
9067
9068std::set<uint32_t> Player::getFinishedQuests() const { return m_finishedQuests; }
9069
9070//////////////////////////////////////////////////////////////////////////////////////////
9071// Social
9073{
9074 if (auto result = CharacterDatabase.Query("SELECT * FROM social_friends WHERE character_guid = %u", getGuidLow()))
9075 {
9076 do
9077 {
9078 SocialFriends socialFriend;
9079
9080 auto* const socialField = result->Fetch();
9081 socialFriend.friendGuid = socialField[1].asUint32();
9082 socialFriend.note = socialField[2].asCString();
9083
9084 m_socialIFriends.push_back(socialFriend);
9085
9086 } while (result->NextRow());
9087 }
9088}
9089
9091{
9092 if (auto result = CharacterDatabase.Query("SELECT character_guid FROM social_friends WHERE friend_guid = %u", getGuidLow()))
9093 {
9094 do
9095 {
9096 auto* const socialField = result->Fetch();
9097 uint32_t friendedByGuid= socialField[0].asUint32();
9098
9099 m_socialFriendedByGuids.push_back(friendedByGuid);
9100
9101 } while (result->NextRow());
9102 }
9103}
9104
9106{
9107 if (auto result = CharacterDatabase.Query("SELECT * FROM social_ignores WHERE character_guid = %u", getGuidLow()))
9108 {
9109 do
9110 {
9111 auto* const ignoreField = result->Fetch();
9112 uint32_t ignoreGuid = ignoreField[1].asUint32();
9113
9114 m_socialIgnoring.push_back(ignoreGuid);
9115
9116 } while (result->NextRow());
9117 }
9118}
9119
9120void Player::addToFriendList(std::string name, std::string note)
9121{
9122 if (auto* targetPlayer = sObjectMgr.getPlayer(name.c_str()))
9123 {
9124 // we can not add us ;)
9125 if (targetPlayer->getGuidLow() == getGuidLow())
9126 {
9128 return;
9129 }
9130
9131 if (targetPlayer->isGMFlagSet())
9132 {
9134 return;
9135 }
9136
9137 if (isFriended(targetPlayer->getGuidLow()))
9138 {
9139 m_session->SendPacket(SmsgFriendStatus(FRIEND_ALREADY, targetPlayer->getGuidLow()).serialise().get());
9140 return;
9141 }
9142
9143 if (targetPlayer->getPlayerInfo()->team != getInitialTeam() && !m_session->hasPermissions() && !worldConfig.player.isInterfactionFriendsEnabled)
9144 {
9145 m_session->SendPacket(SmsgFriendStatus(FRIEND_ENEMY, targetPlayer->getGuidLow()).serialise().get());
9146 return;
9147 }
9148
9149 if (targetPlayer->getSession())
9150 {
9151 m_session->SendPacket(SmsgFriendStatus(FRIEND_ADDED_ONLINE, targetPlayer->getGuidLow(), note, 1,
9152 targetPlayer->getZoneId(), targetPlayer->getLevel(), targetPlayer->getClass()).serialise().get());
9153 }
9154 else
9155 {
9156 m_session->SendPacket(SmsgFriendStatus(FRIEND_ADDED_OFFLINE, targetPlayer->getGuidLow()).serialise().get());
9157 }
9158
9159 // todo: missing FRIEND_LIST_FULL when friend list is full
9160
9161 CharacterDatabase.Execute("INSERT INTO social_friends VALUES(%u, %u, \'%s\')",
9162 getGuidLow(), targetPlayer->getGuidLow(), !note.empty() ? CharacterDatabase.EscapeString(std::string(note)).c_str() : "");
9163
9164 SocialFriends socialFriend;
9165 socialFriend.friendGuid = targetPlayer->getGuidLow();
9166 socialFriend.note = note;
9167
9168 std::lock_guard<std::mutex> guard(m_mutexFriendList);
9169 m_socialIFriends.push_back(socialFriend);
9170 }
9171 else
9172 {
9174 }
9175}
9176
9178{
9179 if (isFriended(guid))
9180 {
9181 m_session->SendPacket(SmsgFriendStatus(FRIEND_REMOVED, guid).serialise().get());
9182
9183 CharacterDatabase.Execute("DELETE FROM social_friends WHERE character_guid = %u AND friend_guid = %u", getGuidLow(), guid);
9184
9185 std::lock_guard<std::mutex> guard(m_mutexFriendList);
9186 m_socialIFriends.erase(std::remove_if(m_socialIFriends.begin(), m_socialIFriends.end(), [&](SocialFriends const& friends) {
9187 return friends.friendGuid == guid;
9188 }),
9189 m_socialIFriends.end());
9190 }
9191 else
9192 {
9194 }
9195}
9196
9197void Player::addNoteToFriend(uint32_t guid, std::string note)
9198{
9199 std::lock_guard<std::mutex> guard(m_mutexFriendList);
9200 for (const auto friends : m_socialIFriends)
9201 {
9202 if (friends.friendGuid == guid)
9203 {
9204 friends.note = note;
9205 CharacterDatabase.Execute("UPDATE social_friends SET note = \'%s\' WHERE character_guid = %u AND friend_guid = %u",
9206 !note.empty() ? CharacterDatabase.EscapeString(note).c_str() : "", getGuidLow(), guid);
9207 }
9208 }
9209}
9210
9212{
9213 std::lock_guard<std::mutex> guard(m_mutexFriendList);
9214 for (const auto friends : m_socialIFriends)
9215 {
9216 if (friends.friendGuid == guid)
9217 return true;
9218 }
9219 return false;
9220}
9221
9222void Player::sendFriendStatus(bool comesOnline)
9223{
9224 std::lock_guard<std::mutex> guard(m_mutexFriendedBy);
9225 if (!m_socialFriendedByGuids.empty())
9226 {
9227 for (auto friendedGuids : m_socialFriendedByGuids)
9228 {
9229 if (auto* targetPlayer = sObjectMgr.getPlayer(friendedGuids))
9230 {
9231 if (targetPlayer->getSession())
9232 {
9233 if (comesOnline)
9234 targetPlayer->sendPacket(SmsgFriendStatus(FRIEND_ONLINE, getGuid(), "", 1, getAreaId(), getLevel(), getClass()).serialise().get());
9235 else
9236 targetPlayer->sendPacket(SmsgFriendStatus(FRIEND_OFFLINE, getGuid()).serialise().get());
9237 }
9238 }
9239 }
9240 }
9241}
9242
9244{
9245 std::vector<SmsgContactListMember> contactMemberList;
9246
9247 if (flags & 0x01) // friend
9248 {
9249 uint32_t maxCount = 0;
9250
9251 std::lock_guard<std::mutex> guard(m_mutexFriendList);
9252 for (auto friends : m_socialIFriends)
9253 {
9254 SmsgContactListMember friendListMember;
9255 friendListMember.guid = friends.friendGuid;
9256 friendListMember.flag = 0x01;
9257 friendListMember.note = friends.note;
9258
9259 if (auto* plr = sObjectMgr.getPlayer(friends.friendGuid))
9260 {
9261 friendListMember.isOnline = 1;
9262 friendListMember.zoneId = plr->getZoneId();
9263 friendListMember.level = plr->getLevel();
9264 friendListMember.playerClass = plr->getClass();
9265 }
9266 else
9267 {
9268 friendListMember.isOnline = 0;
9269 }
9270
9271 contactMemberList.push_back(friendListMember);
9272 ++maxCount;
9273
9274 if (maxCount >= 50)
9275 break;
9276 }
9277
9278 }
9279
9280 if (flags & 0x02) // ignore
9281 {
9282 uint32_t maxCount = 0;
9283
9284 std::lock_guard<std::mutex> guard(m_mutexIgnoreList);
9285 for (auto ignoredGuid : m_socialIgnoring)
9286 {
9287 SmsgContactListMember ignoreListMember;
9288 ignoreListMember.guid = ignoredGuid;
9289 ignoreListMember.flag = 0x02;
9290 ignoreListMember.note = "";
9291
9292 contactMemberList.push_back(ignoreListMember);
9293 ++maxCount;
9294
9295 if (maxCount >= 50)
9296 break;
9297 }
9298 }
9299
9300 sendPacket(SmsgContactList(flags, contactMemberList).serialise().get());
9301}
9302
9303void Player::addToIgnoreList(std::string name)
9304{
9305 if (auto* targetPlayer = sObjectMgr.getPlayer(name.c_str()))
9306 {
9307 // we can not add us ;)
9308 if (targetPlayer->getGuidLow() == getGuidLow())
9309 {
9311 return;
9312 }
9313
9314 if (targetPlayer->isGMFlagSet())
9315 {
9317 return;
9318 }
9319
9320 if (isIgnored(targetPlayer->getGuidLow()))
9321 {
9322 m_session->SendPacket(SmsgFriendStatus(FRIEND_IGNORE_ALREADY, targetPlayer->getGuidLow()).serialise().get());
9323 return;
9324 }
9325
9326 // todo: missing FRIEND_IGNORE_FULL when ignore list is full
9327
9328 CharacterDatabase.Execute("INSERT INTO social_ignores VALUES(%u, %u)", getGuidLow(), targetPlayer->getGuidLow());
9329
9330 std::lock_guard<std::mutex> guard(m_mutexIgnoreList);
9331 m_socialIgnoring.push_back(targetPlayer->getGuidLow());
9332
9333 m_session->SendPacket(SmsgFriendStatus(FRIEND_IGNORE_ADDED, targetPlayer->getGuidLow()).serialise().get());
9334 }
9335 else
9336 {
9338 }
9339}
9340
9342{
9343 if (isIgnored(guid))
9344 {
9345 CharacterDatabase.Execute("DELETE FROM social_ignores WHERE character_guid = %u AND ignore_guid = %u", getGuidLow(), guid);
9346
9347 std::lock_guard<std::mutex> guard(m_mutexIgnoreList);
9348 m_socialIgnoring.erase(std::remove(m_socialIgnoring.begin(), m_socialIgnoring.end(), guid), m_socialIgnoring.end());
9349
9351 }
9352 else
9353 {
9355 }
9356}
9357
9359{
9360 std::lock_guard<std::mutex> guard(m_mutexIgnoreList);
9361 if (std::find(m_socialIgnoring.begin(), m_socialIgnoring.end(), guid) != m_socialIgnoring.end())
9362 return true;
9363
9364 return false;
9365}
9366
9367//////////////////////////////////////////////////////////////////////////////////////////
9368// Hack/Cheat Detection
9370{
9371 m_speedCheatDetector->SkipSamplingUntil(Util::getMSTime() + delay + getSession()->GetLatency() * 2 + 2000);
9372}
9373
9375{
9376 m_speedCheatDetector->EventSpeedChange();
9377}
9378
9379//////////////////////////////////////////////////////////////////////////////////////////
9380// Misc
9382{
9384}
9385
9386void Player::sendMovie([[maybe_unused]]uint32_t movieId)
9387{
9388#if VERSION_STRING > TBC
9389 m_session->SendPacket(SmsgTriggerMovie(movieId).serialise().get());
9390#endif
9391}
9392
9394{
9395#ifdef FT_DUAL_SPEC
9396 return m_specs[m_talentActiveSpec];
9397#else
9398 return m_spec;
9399#endif
9400}
9401
9403{
9404 const auto mapMgr = sMapMgr.findWorldMap(GetMapId(), GetInstanceID());
9405 if (mapMgr && mapMgr->getBaseMap()->isBattlegroundOrArena())
9406 {
9407 const auto battleground = reinterpret_cast<BattlegroundMap*>(mapMgr)->getBattleground();
9408 if (battleground->hasEnded() && battleground->hasFreeSlots(getInitialTeam(), battleground->getType()))
9409 {
9411 {
9414 }
9415 else
9416 {
9419 }
9420 }
9421 }
9422}
9423
9425{
9426 bool success = true;
9428 {
9430 if (transporter)
9431 {
9432 if (isDead())
9433 {
9434 resurrect();
9437 }
9438
9439 const float c_tposx = transporter->GetPositionX() + GetTransOffsetX();
9440 const float c_tposy = transporter->GetPositionY() + GetTransOffsetY();
9441 const float c_tposz = transporter->GetPositionZ() + GetTransOffsetZ();
9442
9443 const LocationVector positionOnTransport = LocationVector(c_tposx, c_tposy, c_tposz, GetOrientation());
9444
9445 if (GetMapId() != transporter->GetMapId())
9446 {
9447 SetMapId(transporter->GetMapId());
9448 sendPacket(AscEmu::Packets::SmsgNewWorld(transporter->GetMapId(), positionOnTransport).serialise().get());
9449
9450 success = false;
9451 }
9452
9453 SetPosition(positionOnTransport.x, positionOnTransport.y, positionOnTransport.z, positionOnTransport.o, false);
9454 transporter->AddPassenger(this);
9455 }
9456 }
9457
9458 return success;
9459}
9460
9462{
9463 bool startOnGMIsland = false;
9464 if (m_session->HasGMPermissions() && m_firstLogin && sWorld.settings.gm.isStartOnGmIslandEnabled)
9465 startOnGMIsland = true;
9466
9467 uint32_t mapId = 1;
9468 float orientation = 0;
9469 float position_x = 16222.6f;
9470 float position_y = 16265.9f;
9471 float position_z = 14.2085f;
9472
9473 if (startOnGMIsland)
9474 {
9475 m_position.ChangeCoords({ position_x, position_y, position_z, orientation });
9476 m_mapId = mapId;
9477
9479 }
9480 else
9481 {
9482 mapId = GetMapId();
9483 orientation = GetOrientation();
9484 position_x = GetPositionX();
9485 position_y = GetPositionY();
9486 position_z = GetPositionZ();
9487 }
9488
9489 sendLoginVerifyWorldPacket(mapId, position_x, position_y, position_z, orientation);
9490}
9491
9493{
9494 m_playerInfo = sObjectMgr.getCachedCharacterInfo(getGuidLow());
9495 if (m_playerInfo == nullptr)
9496 {
9497 auto playerInfo = std::make_unique<CachedCharacterInfo>();
9498 playerInfo->cl = getClass();
9499 playerInfo->gender = getGender();
9500 playerInfo->guid = getGuidLow();
9501 std::string name = getName();
9503 playerInfo->name = name;
9504 playerInfo->lastLevel = getLevel();
9505 playerInfo->lastOnline = UNIXTIME;
9506 playerInfo->lastZone = getZoneId();
9507 playerInfo->race = getRace();
9508 playerInfo->team = getTeam();
9509 playerInfo->guildRank = GUILD_RANK_NONE;
9510 playerInfo->m_Group = nullptr;
9511 playerInfo->subGroup = 0;
9512
9513 m_playerInfo = sObjectMgr.addCachedCharacterInfo(std::move(playerInfo));
9514 }
9515}
9516
9518{
9519 if (getPlayerInfo()->m_guild)
9520 {
9521 if (const auto guild = sGuildMgr.getGuildById(getPlayerInfo()->m_guild))
9522 {
9523 setGuildId(getPlayerInfo()->m_guild);
9524 setGuildRank(getPlayerInfo()->guildRank);
9525 guild->sendLoginInfo(getSession());
9526#if VERSION_STRING >= Cata
9527 setGuildLevel(guild->getLevel());
9528#endif
9529 }
9530 }
9531
9532 if (getPlayerInfo()->m_Group)
9534}
9535
9537{
9538 if (m_firstLogin && !worldConfig.player.skipCinematics)
9539 {
9540#if VERSION_STRING > TBC
9541 if (const auto charEntry = sChrClassesStore.lookupEntry(getClass()))
9542 {
9543 if (charEntry->cinematic_id != 0)
9544 sendPacket(SmsgTriggerCinematic(charEntry->cinematic_id).serialise().get());
9545 else if (const auto raceEntry = sChrRacesStore.lookupEntry(getRace()))
9546 sendPacket(SmsgTriggerCinematic(raceEntry->cinematic_id).serialise().get());
9547 }
9548#else
9549 if (const auto raceEntry = sChrRacesStore.lookupEntry(getRace()))
9550 sendPacket(SmsgTriggerCinematic(raceEntry->cinematic_id).serialise().get());
9551#endif
9552 }
9553}
9554
9559
9561{
9562 if (getPet() == nullptr)
9563 return;
9564
9565#if VERSION_STRING < Mop
9566 m_session->SendPacket(SmsgPetUnlearnConfirm(getPet()->getGuid(), getPet()->getUntrainCost()).serialise().get());
9567#else
9568 m_session->SendPacket(SmsgPetUnlearnConfirm(getPet()->getGuid(), 0).serialise().get());
9569#endif
9570}
9571
9576
9578{
9579#if VERSION_STRING > TBC
9581#endif
9582}
9583
9585{
9587 data << uint32_t(mapid);
9588 sendPacket(&data);
9589}
9590
9592{
9593 m_session->SendPacket(SmsgInstanceDifficulty(difficulty).serialise().get());
9594}
9595
9597{
9598 sendMessageToSet(SmsgCrossedInebriationThreshold(getGuid(), state, itemId).serialise().get(), true);
9599}
9600
9602{
9603 m_session->SendPacket(SmsgSetProficiency(itemClass, proficiency).serialise().get());
9604}
9605
9607{
9608 sendMessageToSet(SmsgPartyKillLog(getGuid(), killedGuid).serialise().get(), true);
9609}
9610
9612{
9613 m_session->SendPacket(SmsgDestroyObject(destroyedGuid).serialise().get());
9614}
9615
9617{
9618#if VERSION_STRING > TBC
9619 m_session->SendPacket(SmsgEquipmentSetUseResult(result).serialise().get());
9620#endif
9621}
9622
9624{
9625 m_session->SendPacket(SmsgTotemCreated(slot, guid, duration, spellId).serialise().get());
9626}
9627
9629{
9631 data << uint8_t(result);
9632 m_session->SendPacket(&data);
9633}
9634
9635void Player::sendGossipPoiPacket(float posX, float posY, uint32_t icon, uint32_t flags, uint32_t data, std::string name)
9636{
9637 m_session->SendPacket(SmsgGossipPoi(flags, posX, posY, icon, data, name).serialise().get());
9638}
9639
9641{
9642 if (const auto pPoi = sMySQLStore.getPointOfInterest(id))
9643 {
9644 const auto loc = (m_session->language > 0) ? sMySQLStore.getLocalizedPointsOfInterest(id, m_session->language) : nullptr;
9645 const auto name = loc ? loc->iconName : pPoi->iconName;
9646
9647 sendGossipPoiPacket(pPoi->x, pPoi->y, pPoi->icon, pPoi->flags, pPoi->data, name);
9648 }
9649}
9650
9655
9657{
9658 m_session->SendPacket(SmsgMeetingstoneSetQueue(dungeonId, status).serialise().get());
9659}
9660
9662{
9663 sendMessageToSet(SmsgPlayObjectSound(soundId, objectGuid).serialise().get(), true);
9664}
9665
9667{
9668 m_session->SendPacket(SmsgPlaySound(soundId).serialise().get());
9669}
9670
9672{
9673 m_session->SendPacket(SmsgExplorationExperience(areaId, experience).serialise().get());
9674}
9675
9677{
9678 m_session->SendPacket(SmsgCooldownEvent(spellId, getGuid()).serialise().get());
9679}
9680
9681#if VERSION_STRING < Cata
9682void Player::sendSpellModifierPacket(uint8_t spellGroup, uint8_t spellType, int32_t modifier, bool isPct)
9683{
9684 if (isPct)
9685 m_session->SendPacket(SmsgSetPctSpellModifier(spellGroup, spellType, modifier).serialise().get());
9686 else
9687 m_session->SendPacket(SmsgSetFlatSpellModifier(spellGroup, spellType, modifier).serialise().get());
9688}
9689#else
9690void Player::sendSpellModifierPacket(uint8_t spellType, std::vector<std::pair<uint8_t, float>> modValues, bool isPct)
9691{
9692 if (isPct)
9693 m_session->SendPacket(SmsgSetPctSpellModifier(spellType, modValues).serialise().get());
9694 else
9695 m_session->SendPacket(SmsgSetFlatSpellModifier(spellType, modValues).serialise().get());
9696}
9697#endif
9698
9699void Player::sendLoginVerifyWorldPacket(uint32_t mapId, float posX, float posY, float posZ, float orientation)
9700{
9701 m_session->SendPacket(SmsgLoginVerifyWorld(mapId, LocationVector(posX, posY, posZ, orientation)).serialise().get());
9702}
9703
9705{
9706 m_session->SendPacket(SmsgMountResult(result).serialise().get());
9707}
9708
9710{
9711 m_session->SendPacket(SmsgDismountResult(result).serialise().get());
9712}
9713
9714void Player::sendCastFailedPacket(uint32_t spellId, uint8_t errorMessage, uint8_t multiCast, uint32_t extra1, uint32_t extra2 /*= 0*/)
9715{
9716 m_session->SendPacket(SmsgCastFailed(multiCast, spellId, errorMessage, extra1, extra2).serialise().get());
9717}
9718
9720{
9721 m_session->SendPacket(SmsgLevelupInfo(level, hp, mana, stat0, stat1, stat2, stat3, stat4).serialise().get());
9722}
9723
9724void Player::sendItemPushResultPacket(bool created, bool recieved, bool sendtoset, uint8_t destbagslot, uint32_t destslot, uint32_t count, uint32_t entry, uint32_t suffix, uint32_t randomprop, uint32_t stack)
9725{
9726 if (sendtoset && isInGroup())
9727 getGroup()->SendPacketToAll(SmsgItemPushResult(getGuid(), recieved, created, destbagslot, destslot, entry, suffix, randomprop, count, stack).serialise().get());
9728 else
9729 m_session->SendPacket(SmsgItemPushResult(getGuid(), recieved, created, destbagslot, destslot, entry, suffix, randomprop, count, stack).serialise().get());
9730}
9731
9733{
9734 sendPacket(SmsgClientControlUpdate(target->GetNewGUID(), allowMove).serialise().get());
9735
9736 if (target == this)
9737 setMover(this);
9738}
9739
9741{
9742 if (!getGuild())
9743 return;
9744
9745 sendPacket(SmsgGuildEvent(GE_MOTD, { getGuild()->getMOTD() }, 0).serialise().get());
9746}
9747
9749{
9750#if VERSION_STRING > TBC
9753 m_session->SendPacket(&data);
9754#endif
9755}
9756
9758{
9759#if VERSION_STRING > TBC
9761 data << uint32_t(setId);
9762 data << WoWGuid(uint64_t(setGuid));
9763 m_session->SendPacket(&data);
9764#endif
9765}
9766
9768{
9769 m_session->SendPacket(SmsgPetSpells(0).serialise().get());
9770}
9771
9773{
9774#if VERSION_STRING < Cata
9777 m_session->SendPacket(&data);
9778#endif
9779}
9780
9782{
9783#if VERSION_STRING > TBC
9784 return getPvpFlags() & PVP_STATE_FLAG_PVP;
9785#else
9786 return getUnitFlags() & UNIT_FLAG_PVP;
9787#endif
9788}
9789
9791{
9792 stopPvPTimer();
9793#if VERSION_STRING > TBC
9794 addPvpFlags(PVP_STATE_FLAG_PVP);
9795 addPlayerFlags(PLAYER_FLAG_PVP_TIMER);
9796#else
9798#endif
9799
9801
9804}
9805
9807{
9808 stopPvPTimer();
9809#if VERSION_STRING > TBC
9810 removePvpFlags(PVP_STATE_FLAG_PVP);
9811 removePlayerFlags(PLAYER_FLAG_PVP_TIMER);
9812#else
9814#endif
9815
9817}
9818
9820{
9821#if VERSION_STRING > TBC
9822 return getPvpFlags() & PVP_STATE_FLAG_FFA_PVP;
9823#else
9824 return hasPlayerFlags(PLAYER_FLAG_FREE_FOR_ALL_PVP);
9825#endif
9826}
9827
9829{
9830 stopPvPTimer();
9831#if VERSION_STRING > TBC
9832 addPvpFlags(PVP_STATE_FLAG_FFA_PVP);
9833#else
9834 addPlayerFlags(PLAYER_FLAG_FREE_FOR_ALL_PVP);
9835#endif
9836
9838}
9839
9841{
9842 stopPvPTimer();
9843#if VERSION_STRING > TBC
9844 removePvpFlags(PVP_STATE_FLAG_FFA_PVP);
9845#else
9846 removePlayerFlags(PLAYER_FLAG_FREE_FOR_ALL_PVP);
9847#endif
9848
9850}
9851
9853{
9854#if VERSION_STRING > TBC
9855 return getPvpFlags() & PVP_STATE_FLAG_SANCTUARY;
9856#elif VERSION_STRING == TBC
9857 return hasPlayerFlags(PLAYER_FLAG_SANCTUARY);
9858#elif VERSION_STRING == Classic
9859 return false;
9860#endif
9861}
9862
9864{
9865#if VERSION_STRING > TBC
9866 addPvpFlags(PVP_STATE_FLAG_SANCTUARY);
9867#elif VERSION_STRING == TBC
9868 addPlayerFlags(PLAYER_FLAG_SANCTUARY);
9869#endif
9870
9872}
9873
9875{
9876#if VERSION_STRING > TBC
9877 removePvpFlags(PVP_STATE_FLAG_SANCTUARY);
9878#elif VERSION_STRING == TBC
9879 removePlayerFlags(PLAYER_FLAG_SANCTUARY);
9880#endif
9881
9883}
9884
9885void Player::sendPvpCredit(uint32_t honor, uint64_t victimGuid, uint32_t victimRank)
9886{
9887 this->sendPacket(SmsgPvpCredit(honor, victimGuid, victimRank).serialise().get());
9888}
9889
9891{
9892 this->sendPacket(SmsgRaidGroupOnly(timeInMs, type).serialise().get());
9893}
9894
9896{
9897 if (item)
9898 {
9899 setVisibleItemEntry(slot, item->getVisibleEntry());
9900#if VERSION_STRING > TBC
9903#else
9904 for (uint8_t i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i)
9906#endif
9907 }
9908 else
9909 {
9910 setVisibleItemEntry(slot, 0);
9911#if VERSION_STRING > TBC
9914#else
9915 for (uint8_t i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i)
9916 setVisibleItemEnchantment(slot, i, 0);
9917#endif
9918 }
9919}
9920
9921#if VERSION_STRING == Cata
9923{
9924 if (!item)
9925 return;
9926
9927 WDB::Structures::ItemReforgeEntry const* reforge = sItemReforgeStore.lookupEntry(item->getEnchantmentId(REFORGE_ENCHANTMENT_SLOT));
9928 if (!reforge)
9929 return;
9930
9931 auto removeValue = static_cast<int32_t>(item->getReforgableStat(ItemModType(reforge->SourceStat)) * reforge->SourceMultiplier);
9932 auto addValue = static_cast<int32_t>(removeValue * reforge->FinalMultiplier);
9933
9934 switch (reforge->SourceStat)
9935 {
9936 case ITEM_MOD_MANA:
9937 modifyBonuses(ITEM_MOD_MANA, -removeValue, apply);
9938 break;
9939 case ITEM_MOD_HEALTH:
9940 modifyBonuses(ITEM_MOD_HEALTH, -removeValue, apply);
9941 break;
9942 case ITEM_MOD_AGILITY:
9943 modifyBonuses(ITEM_MOD_AGILITY, -removeValue, apply);
9944 break;
9945 case ITEM_MOD_STRENGTH:
9946 modifyBonuses(ITEM_MOD_STRENGTH, -removeValue, apply);
9947 break;
9948 case ITEM_MOD_INTELLECT:
9949 modifyBonuses(ITEM_MOD_INTELLECT, -removeValue, apply);
9950 break;
9951 case ITEM_MOD_SPIRIT:
9952 modifyBonuses(ITEM_MOD_SPIRIT, -removeValue, apply);
9953 break;
9954 case ITEM_MOD_STAMINA:
9955 modifyBonuses(ITEM_MOD_STAMINA, -removeValue, apply);
9956 break;
9958 modifyBonuses(ITEM_MOD_DEFENSE_RATING, -removeValue, apply);
9959 break;
9961 modifyBonuses(ITEM_MOD_DODGE_RATING, -removeValue, apply);
9962 break;
9964 modifyBonuses(ITEM_MOD_PARRY_RATING, -removeValue, apply);
9965 break;
9967 modifyBonuses(ITEM_MOD_SHIELD_BLOCK_RATING, -removeValue, apply);
9968 break;
9970 modifyBonuses(ITEM_MOD_MELEE_HIT_RATING, -removeValue, apply);
9971 break;
9973 modifyBonuses(ITEM_MOD_RANGED_HIT_RATING, -removeValue, apply);
9974 break;
9976 modifyBonuses(ITEM_MOD_SPELL_HIT_RATING, -removeValue, apply);
9977 break;
9980 break;
9983 break;
9986 break;
9988 modifyBonuses(ITEM_MOD_SPELL_HASTE_RATING, -removeValue, apply);
9989 break;
9991 modifyBonuses(ITEM_MOD_HIT_RATING, -removeValue, apply);
9992 break;
9994 modifyBonuses(ITEM_MOD_CRITICAL_STRIKE_RATING, -removeValue, apply);
9995 break;
9997 modifyBonuses(ITEM_MOD_RESILIENCE_RATING, -removeValue, apply);
9998 break;
10000 modifyBonuses(ITEM_MOD_HASTE_RATING, -removeValue, apply);
10001 break;
10003 modifyBonuses(ITEM_MOD_EXPERTISE_RATING, -removeValue, apply);
10004 break;
10006 modifyBonuses(ITEM_MOD_ATTACK_POWER, -removeValue, apply);
10007 break;
10009 modifyBonuses(ITEM_MOD_RANGED_ATTACK_POWER, -removeValue, apply);
10010 break;
10012 modifyBonuses(ITEM_MOD_MANA_REGENERATION , -removeValue, apply);
10013 break;
10016 break;
10018 modifyBonuses(ITEM_MOD_SPELL_POWER , -removeValue, apply);
10019 break;
10020 /*case ITEM_MOD_HEALTH_REGEN: // todo dunno where these are handled
10021 -int32_t(removeValue)
10022 break;
10023 case ITEM_MOD_SPELL_PENETRATION:
10024 -int32_t(removeValue)
10025 break;
10026 case ITEM_MOD_BLOCK_VALUE:
10027 -removeValue
10028 break;*/
10029 }
10030
10031 switch (reforge->FinalStat)
10032 {
10033 case ITEM_MOD_MANA:
10034 modifyBonuses(ITEM_MOD_MANA, addValue, apply);
10035 break;
10036 case ITEM_MOD_HEALTH:
10037 modifyBonuses(ITEM_MOD_HEALTH, addValue, apply);
10038 break;
10039 case ITEM_MOD_AGILITY:
10040 modifyBonuses(ITEM_MOD_AGILITY, addValue, apply);
10041 break;
10042 case ITEM_MOD_STRENGTH:
10043 modifyBonuses(ITEM_MOD_STRENGTH, addValue, apply);
10044 break;
10045 case ITEM_MOD_INTELLECT:
10046 modifyBonuses(ITEM_MOD_INTELLECT, addValue, apply);
10047 break;
10048 case ITEM_MOD_SPIRIT:
10049 modifyBonuses(ITEM_MOD_SPIRIT, addValue, apply);
10050 break;
10051 case ITEM_MOD_STAMINA:
10052 modifyBonuses(ITEM_MOD_STAMINA, addValue, apply);
10053 break;
10055 modifyBonuses(ITEM_MOD_DEFENSE_RATING, addValue, apply);
10056 break;
10058 modifyBonuses(ITEM_MOD_DODGE_RATING, addValue, apply);
10059 break;
10061 modifyBonuses(ITEM_MOD_PARRY_RATING, addValue, apply);
10062 break;
10065 break;
10067 modifyBonuses(ITEM_MOD_MELEE_HIT_RATING, addValue, apply);
10068 break;
10070 modifyBonuses(ITEM_MOD_RANGED_HIT_RATING, addValue, apply);
10071 break;
10073 modifyBonuses(ITEM_MOD_SPELL_HIT_RATING, addValue, apply);
10074 break;
10077 break;
10080 break;
10083 break;
10086 break;
10088 modifyBonuses(ITEM_MOD_HIT_RATING, addValue, apply);
10089 break;
10092 break;
10094 modifyBonuses(ITEM_MOD_RESILIENCE_RATING, addValue, apply);
10095 break;
10097 modifyBonuses(ITEM_MOD_HASTE_RATING, addValue, apply);
10098 break;
10100 modifyBonuses(ITEM_MOD_EXPERTISE_RATING, addValue, apply);
10101 break;
10103 modifyBonuses(ITEM_MOD_ATTACK_POWER, addValue, apply);
10104 break;
10107 break;
10109 modifyBonuses(ITEM_MOD_MANA_REGENERATION, addValue, apply);
10110 break;
10112 modifyBonuses(CR_ARMOR_PENETRATION, addValue, apply);
10113 break;
10115 modifyBonuses(ITEM_MOD_SPELL_POWER, addValue, apply);
10116 break;
10117 /*case ITEM_MOD_HEALTH_REGEN: // todo dunno where these are handled
10118 int32_t(addValue)
10119 break;
10120 case ITEM_MOD_SPELL_PENETRATION:
10121 int32_t(addValue)
10122 break;
10123 case ITEM_MOD_BLOCK_VALUE:
10124 addValue
10125 break;*/
10126 }
10127
10128 updateStats();
10129}
10130#elif VERSION_STRING > Cata
10131void Player::applyReforgeEnchantment(Item* item, bool apply)
10132{
10133 // TODO mop
10134}
10135#endif
10136
10138{
10139 if (!pRewardSource)
10140 return false;
10141
10142 Object* player = nullptr;
10143 const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow());
10144 if (corpse)
10145 player = sObjectMgr.getPlayer(static_cast<uint32_t>(corpse->getOwnerGuid()));
10146
10147 if (!player || isAlive())
10148 player = this;
10149
10150 if (player->GetMapId() != pRewardSource->GetMapId() || player->GetInstanceID() != pRewardSource->GetInstanceID())
10151 return false;
10152
10153 return pRewardSource->getDistance(player) <= 75.0f;
10154}
10155
10157{
10158 if (object->isCreatureOrPlayer())
10159 {
10160#if VERSION_STRING < Mop
10161 object->forceBuildUpdateValueForField(getOffsetForStructuredField(WoWUnit, dynamic_flags), this);
10162#else
10163 object->forceBuildUpdateValueForField(getOffsetForStructuredField(WoWObject, dynamic_field), this);
10164#endif
10165 }
10166}
10167
10168#if VERSION_STRING > TBC
10169AchievementMgr* Player::getAchievementMgr() { return m_achievementMgr.get(); }
10170#endif
10171
10172void Player::sendUpdateDataToSet(ByteBuffer* groupBuf, ByteBuffer* nonGroupBuf, bool sendToSelf)
10173{
10174 if (groupBuf && nonGroupBuf)
10175 {
10176 for (const auto& object : getInRangePlayersSet())
10177 {
10178 if (Player* player = static_cast<Player*>(object))
10179 {
10180 if (player->getGroup() && getGroup() && player->getGroup()->GetID() == getGroup()->GetID())
10181 player->getUpdateMgr().pushUpdateData(groupBuf, 1);
10182 else
10183 player->getUpdateMgr().pushUpdateData(nonGroupBuf, 1);
10184 }
10185 }
10186 }
10187 else
10188 {
10189 if (groupBuf && nonGroupBuf == nullptr)
10190 {
10191 for (const auto& object : getInRangePlayersSet())
10192 {
10193 if (Player* player = static_cast<Player*>(object))
10194 if (player->getGroup() && getGroup() && player->getGroup()->GetID() == getGroup()->GetID())
10195 player->getUpdateMgr().pushUpdateData(groupBuf, 1);
10196 }
10197 }
10198 else
10199 {
10200 if (groupBuf == nullptr && nonGroupBuf)
10201 {
10202 for (const auto& object : getInRangePlayersSet())
10203 {
10204 if (Player* player = static_cast<Player*>(object))
10205 if (player->getGroup() == nullptr || player->getGroup()->GetID() != getGroup()->GetID())
10206 player->getUpdateMgr().pushUpdateData(nonGroupBuf, 1);
10207 }
10208 }
10209 }
10210 }
10211
10212 if (sendToSelf && groupBuf != nullptr)
10213 getUpdateMgr().pushUpdateData(groupBuf, 1);
10214}
10215
10217{
10218 m_session->SendPacket(SmsgUpdateWorldState(worldState, value).serialise().get());
10219}
10220
10222{
10223 if (vendor == nullptr)
10224 return true;
10225
10226 if (vendor->flags == RESTRICTION_CHECK_ALL)
10227 {
10228 if ((vendor->racemask > 0) && !(getRaceMask() & vendor->racemask))
10229 return false;
10230
10231 if ((vendor->classmask > 0) && !(getClassMask() & vendor->classmask))
10232 return false;
10233
10234 if (vendor->reqrepfaction)
10235 {
10236 uint32_t plrep = getFactionStanding(vendor->reqrepfaction);
10237 if (plrep < vendor->reqrepvalue)
10238 return false;
10239 }
10240 }
10241 else if (vendor->flags == RESTRICTION_CHECK_MOUNT_VENDOR)
10242 {
10243 if ((vendor->racemask > 0) && (vendor->reqrepfaction))
10244 {
10245 uint32_t plrep = getFactionStanding(vendor->reqrepfaction);
10246 if (!(getRaceMask() & vendor->racemask) && (plrep < vendor->reqrepvalue))
10247 return false;
10248 }
10249 else
10250 {
10251 sLogger.failure("VendorRestrictions: Mount vendor specified, but not enough m_playerCreateInfo for creature {}", vendor->entry);
10252 }
10253 }
10254
10255 return true;
10256}
10257
10258bool Player::canTrainAt(Trainer const* trainer)
10259{
10260 if (!trainer)
10261 return false;
10262
10263 if ((trainer->RequiredClass && this->getClass() != trainer->RequiredClass) ||
10264 ((trainer->RequiredRace && this->getRace() != trainer->RequiredRace) &&
10265 ((trainer->RequiredRepFaction && trainer->RequiredRepValue) &&
10266 this->getFactionStanding(trainer->RequiredRepFaction) != static_cast<int32_t>(trainer->RequiredRepValue))) ||
10267 (trainer->RequiredSkill && !this->hasSkillLine(trainer->RequiredSkill)) ||
10268 (trainer->RequiredSkillLine && this->getSkillLineCurrent(trainer->RequiredSkill) < trainer->RequiredSkillLine))
10269 {
10270 return false;
10271 }
10272
10273 return true;
10274}
10275
10277{
10279 SetPosition(float(GetPositionX() + 0.01), float(GetPositionY() + 0.01), float(GetPositionZ() + 0.01), GetOrientation());
10280 m_session->SendPacket(SmsgTriggerCinematic(id).serialise().get());
10281}
10282
10284{
10286 m_controledUnit = target;
10287
10288#if VERSION_STRING > WotLK
10289 ObjectGuid guid = target->getGuid();
10290
10292 data.writeBit(guid[5]);
10293 data.writeBit(guid[7]);
10294 data.writeBit(guid[3]);
10295 data.writeBit(guid[6]);
10296 data.writeBit(guid[0]);
10297 data.writeBit(guid[4]);
10298 data.writeBit(guid[1]);
10299 data.writeBit(guid[2]);
10300
10301 data.WriteByteSeq(guid[6]);
10302 data.WriteByteSeq(guid[2]);
10303 data.WriteByteSeq(guid[3]);
10304 data.WriteByteSeq(guid[0]);
10305 data.WriteByteSeq(guid[5]);
10306 data.WriteByteSeq(guid[7]);
10307 data.WriteByteSeq(guid[1]);
10308 data.WriteByteSeq(guid[4]);
10309
10310 sendPacket(&data);
10311#endif
10312}
10313
10315{
10317 m_timeSyncTimer = 0;
10318 m_timeSyncClient = 0;
10320}
10321
10323{
10325
10326 // Schedule next sync in 10 sec
10327 m_timeSyncTimer = 10000;
10329}
10330
10331/////////////////////////////////////////////////////////////////////////////////////////
10332// Void Storage
10333#if VERSION_STRING > WotLK
10334void Player::loadVoidStorage()
10335{
10336 auto result = CharacterDatabase.Query("SELECT itemid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor FROM character_void_storage WHERE playerGuid = %u", getGuidLow());
10337 if (!result)
10338 return;
10339
10340 do
10341 {
10342 Field* fields = result->Fetch();
10343
10344 uint64_t itemId = fields[0].asUint64();
10345 uint32_t itemEntry = fields[1].asUint32();
10346 uint8_t slot = fields[2].asUint8();
10347 uint32_t creatorGuid = fields[3].asUint32();
10348 uint32_t randomProperty = fields[4].asUint32();
10349 uint32_t suffixFactor = fields[5].asUint32();
10350
10351 if (!itemId)
10352 {
10353 sLogger.debug("Player::loadVoidStorage - Player (GUID: {}, name: {}) has an item with an invalid id (item id: %I64u, entry: {}).", getGuidLow(), getName(), itemId, itemEntry);
10354 continue;
10355 }
10356
10357 if (!sMySQLStore.getItemProperties(itemEntry))
10358 {
10359 sLogger.debug("Player::loadVoidStorage - Player (GUID: {}, name: {}) has an item with an invalid entry (item id: %I64u, entry: {}).", getGuidLow(), getName(), itemId, itemEntry);
10360 continue;
10361 }
10362
10363 if (slot >= VOID_STORAGE_MAX_SLOT)
10364 {
10365 sLogger.debug("Player::loadVoidStorage - Player (GUID: {}, name: {}) has an item with an invalid slot (item id: %I64u, entry: {}, slot: {}).", getGuidLow(), getName(), itemId, itemEntry, slot);
10366 continue;
10367 }
10368
10369 if (!sObjectMgr.getPlayer(creatorGuid))
10370 {
10371 sLogger.debug("Player::loadVoidStorage - Player (GUID: {}, name: {}) has an item with an invalid creator guid, set to 0 (item id: %I64u, entry: {}, creatorGuid: {}).", getGuidLow(), getName(), itemId, itemEntry, creatorGuid);
10372 creatorGuid = 0;
10373 }
10374
10375 _voidStorageItems[slot] = std::make_unique<VoidStorageItem>(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor);
10376 } while (result->NextRow());
10377}
10378
10379void Player::saveVoidStorage()
10380{
10381 uint32_t lowGuid = getGuidLow();
10382
10383 for (uint8_t slot = 0; slot < VOID_STORAGE_MAX_SLOT; ++slot)
10384 {
10385 if (!_voidStorageItems[slot]) // unused item
10386 {
10387 // DELETE FROM void_storage WHERE slot = ? AND playerGuid = ?
10388 CharacterDatabase.Execute("DELETE FROM character_void_storage WHERE playerGuid = %u AND slot = %u ", lowGuid, slot);
10389 }
10390 else
10391 {
10392 std::stringstream ss;
10393 ss << "REPLACE INTO character_void_storage VALUES(";
10394 ss << _voidStorageItems[slot]->itemId << ",";
10395 ss << lowGuid << ",";
10396 ss << uint32_t(_voidStorageItems[slot]->itemEntry) << ",";
10397 ss << int(slot) << ",";
10398 ss << _voidStorageItems[slot]->creatorGuid << ",";
10399 ss << _voidStorageItems[slot]->itemRandomPropertyId << ",";
10400 ss << _voidStorageItems[slot]->itemSuffixFactor;
10401 ss << ")";
10402 CharacterDatabase.Execute(ss.str().c_str());
10403 }
10404 }
10405}
10406
10407bool Player::isVoidStorageUnlocked() const { return hasPlayerFlags(PLAYER_FLAG_VOID_STORAGE_UNLOCKED); }
10408void Player::unlockVoidStorage() { addPlayerFlags(PLAYER_FLAG_VOID_STORAGE_UNLOCKED); }
10409void Player::lockVoidStorage() { removePlayerFlags(PLAYER_FLAG_VOID_STORAGE_UNLOCKED); }
10410
10411uint8_t Player::getNextVoidStorageFreeSlot() const
10412{
10413 for (uint8_t i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
10414 if (!_voidStorageItems[i]) // unused item
10415 return i;
10416
10417 return VOID_STORAGE_MAX_SLOT;
10418}
10419
10420uint8_t Player::getNumOfVoidStorageFreeSlots() const
10421{
10422 uint8_t count = 0;
10423
10424 for (uint8_t i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
10425 if (!_voidStorageItems[i])
10426 count++;
10427
10428 return count;
10429}
10430
10431uint8_t Player::addVoidStorageItem(const VoidStorageItem& item)
10432{
10433 int8_t slot = getNextVoidStorageFreeSlot();
10434
10435 if (slot >= VOID_STORAGE_MAX_SLOT)
10436 {
10438 return 255;
10439 }
10440
10441 _voidStorageItems[slot] = std::make_unique<VoidStorageItem>(item.itemId, item.itemEntry,
10443 return slot;
10444}
10445
10446void Player::addVoidStorageItemAtSlot(uint8_t slot, const VoidStorageItem& item)
10447{
10448 if (slot >= VOID_STORAGE_MAX_SLOT)
10449 {
10451 return;
10452 }
10453
10454 if (_voidStorageItems[slot])
10455 {
10456 sLogger.debug("Player::addVoidStorageItemAtSlot - Player (GUID: {}, name: {}) tried to add an item to an used slot (item id: {}, entry: {}, slot: {}).", getGuidLow(), getName(), _voidStorageItems[slot]->itemId, _voidStorageItems[slot]->itemEntry, slot);
10458 return;
10459 }
10460
10461 _voidStorageItems[slot] = std::make_unique<VoidStorageItem>(item.itemId, item.itemEntry,
10463}
10464
10465void Player::deleteVoidStorageItem(uint8_t slot)
10466{
10467 if (slot >= VOID_STORAGE_MAX_SLOT)
10468 {
10470 return;
10471 }
10472
10473 _voidStorageItems[slot] = nullptr;
10474}
10475
10476bool Player::swapVoidStorageItem(uint8_t oldSlot, uint8_t newSlot)
10477{
10478 if (oldSlot >= VOID_STORAGE_MAX_SLOT || newSlot >= VOID_STORAGE_MAX_SLOT || oldSlot == newSlot)
10479 return false;
10480
10481 std::swap(_voidStorageItems[newSlot], _voidStorageItems[oldSlot]);
10482 return true;
10483}
10484
10485VoidStorageItem* Player::getVoidStorageItem(uint8_t slot) const
10486{
10487 if (slot >= VOID_STORAGE_MAX_SLOT)
10488 {
10490 return nullptr;
10491 }
10492
10493 return _voidStorageItems[slot] != nullptr ? _voidStorageItems[slot].get() : nullptr;
10494}
10495
10496VoidStorageItem* Player::getVoidStorageItem(uint64_t id, uint8_t& slot) const
10497{
10498 for (uint8_t i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
10499 {
10500 if (_voidStorageItems[i] && _voidStorageItems[i]->itemId == id)
10501 {
10502 slot = i;
10503 return _voidStorageItems[i].get();
10504 }
10505 }
10506
10507 return nullptr;
10508}
10509#endif
10510
10511/////////////////////////////////////////////////////////////////////////////////////////
10512// Taxi
10513bool Player::activateTaxiPathTo(std::vector<uint32_t> const& nodes, Creature* npc /*= nullptr*/, uint32_t spellid /*= 0*/)
10514{
10515 if (nodes.size() < 2)
10516 return false;
10517
10518 // not let cheating with start flight in time of logout process || while in combat || has type state: stunned || has type state: root
10520 {
10522 return false;
10523 }
10524
10526 return false;
10527
10528 // taximaster case
10529 if (npc)
10530 {
10531 // not let cheating with start flight mounted
10532 if (isMounted())
10533 {
10535 return false;
10536 }
10537
10539 {
10541 return false;
10542 }
10543 }
10544 // cast case or scripted call case
10545 else
10546 {
10548
10551
10553 if (spell->getSpellInfo()->getId() != spellid)
10555
10557
10559 if (spell->getSpellInfo()->getId() != spellid)
10561 }
10562
10563 uint32_t sourcenode = nodes[0];
10564
10565 // starting node too far away (cheat?)
10566 WDB::Structures::TaxiNodesEntry const* node = sTaxiNodesStore.lookupEntry(sourcenode);
10567 if (!node)
10568 {
10570 return false;
10571 }
10572
10573 // Prepare to flight start now
10574#if VERSION_STRING > TBC
10575 exitVehicle();
10576#endif
10577
10578 // stop trade (client cancel trade at taxi map open but cheating tools can be used for reopen it)
10579 cancelTrade(true);
10580
10581 // clean not finished taxi path if any
10582 m_taxi->clearTaxiDestinations();
10583
10584 // 0 element current node
10585 m_taxi->addTaxiDestination(sourcenode);
10586
10587 // fill destinations path tail
10588 uint32_t sourcepath = 0;
10589 uint32_t totalcost = 0;
10590 uint32_t firstcost = 0;
10591
10592 uint32_t prevnode = sourcenode;
10593 uint32_t lastnode;
10594
10595 for (uint32_t i = 1; i < nodes.size(); ++i)
10596 {
10597 uint32_t path, cost;
10598
10599 lastnode = nodes[i];
10600 sTaxiMgr.getTaxiPath(prevnode, lastnode, path, cost);
10601
10602 if (!path)
10603 {
10604 m_taxi->clearTaxiDestinations();
10605 return false;
10606 }
10607
10608 totalcost += cost;
10609 if (i == 1)
10610 firstcost = cost;
10611
10612 if (prevnode == sourcenode)
10613 sourcepath = path;
10614
10615 m_taxi->addTaxiDestination(lastnode);
10616
10617 prevnode = lastnode;
10618 }
10619
10620 // get mount model (in case non taximaster (npc == nullptr) allow more wide lookup)
10621 uint32_t mount_display_id = sTaxiMgr.getTaxiMountDisplayId(sourcenode, GetTeam(), npc == nullptr || (sourcenode == 315 && getClass() == DEATHKNIGHT));
10622
10623 // in spell case allow 0 model
10624 if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0)
10625 {
10627 m_taxi->clearTaxiDestinations();
10628 return false;
10629 }
10630
10631 uint64_t money = getCoinage();
10632
10633 if (npc)
10634 {
10635 // Disocunting todo
10636 float discount = 1.0f;
10637 totalcost = uint32_t(ceil(totalcost * discount));
10638 firstcost = uint32_t(round(firstcost * discount));
10639 }
10640
10641 if (money < totalcost)
10642 {
10644 m_taxi->clearTaxiDestinations();
10645 return false;
10646 }
10647
10648 //Checks and preparations done, DO FLIGHT
10649#if VERSION_STRING > TBC
10650 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1);
10651#endif
10652
10653 // prevent stealth flight
10654 modCoinage(-(int64_t)firstcost);
10655#if VERSION_STRING > TBC
10656 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost);
10657#endif
10659 getSession()->sendDoFlight(mount_display_id, sourcepath);
10660 return true;
10661}
10662
10663bool Player::activateTaxiPathTo(uint32_t taxi_path_id, uint32_t spellid /*= 0*/)
10664{
10665 WDB::Structures::TaxiPathEntry const* entry = sTaxiPathStore.lookupEntry(taxi_path_id);
10666 if (!entry)
10667 return false;
10668
10669 std::vector<uint32_t> nodes;
10670
10671 nodes.resize(2);
10672 nodes[0] = entry->from;
10673 nodes[1] = entry->to;
10674
10675 return activateTaxiPathTo(nodes, nullptr, spellid);
10676}
10677
10679{
10680 WDB::Structures::TaxiPathEntry const* entry = sTaxiPathStore.lookupEntry(taxi_path_id);
10681 if (!entry)
10682 return false;
10683
10684 std::vector<uint32_t> nodes;
10685
10686 nodes.resize(2);
10687 nodes[0] = entry->from;
10688 nodes[1] = entry->to;
10689
10690 return activateTaxiPathTo(nodes, npc);
10691}
10692
10694{
10695 m_taxi->clearTaxiDestinations(); // not destinations, clear source node
10696 dismount();
10698}
10699
10701{
10702 uint32_t sourceNode = m_taxi->getTaxiSource();
10703 if (!sourceNode)
10704 return;
10705
10706 uint32_t mountDisplayId = sTaxiMgr.getTaxiMountDisplayId(sourceNode, getTeam(), true);
10707 if (!mountDisplayId)
10708 return;
10709
10710 uint32_t path = m_taxi->getCurrentTaxiPath();
10711
10712 // search appropriate start path node
10713 uint32_t startNode = m_taxi->nodeAfterTeleport;
10714
10715 TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path];
10716
10717 float distPrev;
10718 float distNext = getExactDistSq(nodeList[0]->x, nodeList[0]->y, nodeList[0]->z);
10719
10720 for (uint32_t i = 1; i < nodeList.size(); ++i)
10721 {
10722 WDB::Structures::TaxiPathNodeEntry const* node = nodeList[i];
10723 WDB::Structures::TaxiPathNodeEntry const* prevNode = nodeList[i - 1];
10724
10725 // skip nodes at another map
10726 if (node->mapid != GetMapId())
10727 continue;
10728
10729 distPrev = distNext;
10730
10731 distNext = getExactDistSq(node->x, node->y, node->z);
10732
10733 float distNodes =
10734 (node->x - prevNode->x) * (node->x - prevNode->x) +
10735 (node->y - prevNode->y) * (node->y - prevNode->y) +
10736 (node->z - prevNode->z) * (node->z - prevNode->z);
10737
10738 if (distNext + distPrev < distNodes)
10739 {
10740 startNode = i;
10741 break;
10742 }
10743 }
10744
10745 getSession()->sendDoFlight(mountDisplayId, path, startNode);
10746}
10747
10749{
10750 for (const auto& itr : getInRangeObjectsSet())
10751 {
10752 if (!itr->isCreature())
10753 continue;
10754
10755 Creature* creature = itr->ToCreature();
10756 if (!creature || creature->isHostileTo(this))
10757 continue;
10758
10759 if (!creature->isTaxi())
10760 continue;
10761
10762 const auto nearestNode = sTaxiMgr.getNearestTaxiNode(creature->GetPosition(), creature->GetMapId(), GetTeam());
10763 if (nearestNode == 0)
10764 continue;
10765
10766 getSession()->SendPacket(SmsgTaxinodeStatus(creature->getGuid(), m_taxi->isTaximaskNodeKnown(nearestNode)).serialise().get());
10767 }
10768}
10769
10771{
10773}
10774
10776{
10777 return !m_taxi->empty();
10778}
10779
10781{
10782 m_taxi->initTaxiNodesForLevel(getRace(), getClass(), getLevel());
10783}
10784
10785/////////////////////////////////////////////////////////////////////////////////////////
10786// Loot
10787const uint64_t& Player::getLootGuid() const { return m_lootGuid; }
10788void Player::setLootGuid(const uint64_t& guid) { m_lootGuid = guid; }
10789
10790//\note: Types 1 corpse/go; 2 skinning/herbalism/minning; 3 fishing
10791void Player::sendLoot(uint64_t guid, uint8_t loot_type, uint32_t mapId)
10792{
10793 if (!IsInWorld())
10794 return;
10795
10796 Loot* pLoot = nullptr;
10797
10798 WoWGuid wowGuid;
10799 wowGuid.Init(guid);
10800
10801 if (wowGuid.isUnit())
10802 {
10803 Creature* pCreature = getWorldMap()->getCreature(wowGuid.getGuidLowPart());
10804 if (!pCreature)return;
10805 pLoot = &pCreature->loot;
10806 m_currentLoot = pCreature->getGuid();
10807
10808 }
10809 else if (wowGuid.isGameObject())
10810 {
10812
10813 if (!go)
10814 {
10815 SmsgLootReleaseResponse(guid, 1);
10816 return;
10817 }
10818
10819 if (loot_type == LOOT_SKINNING)
10820 {
10821 // Disarm Trap
10822 if (!go->IsWithinDistInMap(this, 20.f))
10823 {
10824 SmsgLootReleaseResponse(guid, 1);
10825 return;
10826 }
10827 }
10828 else
10829 {
10830 if (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->getCreatedByGuid() != getGuid()) && !go->IsWithinDistInMap(this, 30.0f))
10831 {
10832 SmsgLootReleaseResponse(guid, 1);
10833 return;
10834 }
10835
10836 if (loot_type == LOOT_CORPSE && go->getRespawnTime() && go->isSpawnedByDefault())
10837 {
10838 SmsgLootReleaseResponse(guid, 1);
10839 return;
10840 }
10841 }
10842
10843 GameObject_Lootable* pLGO = static_cast<GameObject_Lootable*>(go);
10844 pLoot = &pLGO->loot;
10845
10846 // loot was generated and respawntime has passed since then, allow to recreate loot
10847 // to avoid bugs, this rule covers spawned gameobjects only
10848 // Don't allow to regenerate chest loot inside instances and raids
10851
10852 if (go->getLootState() == GO_READY)
10853 {
10854 uint32_t lootid = go->GetGameObjectProperties()->getLootId();
10855 if (lootid)
10856 {
10857 pLoot->clear();
10858
10859 auto group = getGroup();
10861
10862 // check current RR player and get next if necessary
10863 if (groupRules)
10864 group->updateLooterGuid(go);
10865
10866 pLoot->fillLoot(lootid, sLootMgr.getGameobjectLoot(), this, false, static_cast<uint8_t>(pLGO->getLootMode()));
10867 pLGO->setLootGenerationTime();
10868
10869 // get next RR player (for next loot)
10870 if (groupRules && !pLoot->empty())
10871 group->updateLooterGuid(go);
10872 }
10873
10874 if (loot_type == LOOT_FISHING || loot_type == LOOT_FISHING_JUNK)
10875 pLGO->getFishLoot(this, loot_type == LOOT_FISHING_JUNK);
10876
10877 go->setLootState(GO_ACTIVATED, this);
10878
10879 // set Current Looter
10880 m_currentLoot = pLGO->getGuid();
10881 }
10882 }
10883 else if (wowGuid.isPlayer())
10884 {
10885 Player* p = getWorldMap()->getPlayer((uint32_t)guid);
10886 if (!p)
10887 return;
10888
10889 pLoot = &p->loot;
10890 m_currentLoot = p->getGuid();
10891 }
10892 else if (wowGuid.isCorpse())
10893 {
10894 if (const auto corpse = sObjectMgr.getCorpseByGuid(static_cast<uint32_t>(guid)))
10895 {
10896 pLoot = &corpse->loot;
10897 m_currentLoot = corpse->getGuid();
10898 }
10899 }
10900 else if (wowGuid.isItem())
10901 {
10902 Item* pItem = getItemInterface()->GetItemByGUID(guid);
10903 if (!pItem)
10904 return;
10905 pLoot = pItem->m_loot.get();
10906 m_currentLoot = pItem->getGuid();
10907 }
10908
10909 if (!pLoot)
10910 {
10911 // something whack happened.. damn cheaters..
10912 return;
10913 }
10914
10915 // add to looter set
10916 pLoot->addLooter(getGuidLow());
10917
10918 // Group case
10919 PartyLootMethod loot_method;
10920
10921 // Send Roll packets
10922 if (getGroup())
10923 {
10924 loot_method = PartyLootMethod(getGroup()->GetMethod());
10925
10926 switch (loot_method)
10927 {
10928 case PARTY_LOOT_GROUP:
10929 getGroup()->sendGroupLoot(pLoot, getWorldMap()->getObject(m_currentLoot), this, mapId);
10930 break;
10935 break;
10936 }
10937 }
10938 else
10939 {
10940 loot_method = PARTY_LOOT_FREE_FOR_ALL;
10941 }
10942
10943 m_lootGuid = guid;
10944
10945 WorldPacket data;
10947 data << uint64_t(guid);
10948 data << uint8_t(loot_type); //loot_type;
10949
10950
10951 data << uint32_t(pLoot->gold); // gold
10952 data << uint8_t(0); //loot size reserve
10953#if VERSION_STRING >= Cata
10954 data << uint8_t(0); // currency count reserve
10955#endif
10956
10957 uint32_t maxItemsCount = 0;
10958
10959 // Non Personal Items
10960 auto item = pLoot->items.begin();
10961 for (uint32_t nonpersonalItemsCount = 0; item != pLoot->items.end(); ++item, nonpersonalItemsCount++)
10962 {
10963 if (item->is_looted)
10964 continue;
10965
10966 if (item->is_ffa)
10967 continue;
10968
10970 if (loot_type < 2)
10971 {
10972 switch (loot_method)
10973 {
10975 {
10976 if (!item->is_looted && !item->is_ffa && item->isAllowedForPlayer(this))
10977 slottype = LOOT_SLOT_TYPE_MASTER;
10978 else
10979 // dont show item
10980 continue;
10981 }
10982 break;
10984 case PARTY_LOOT_GROUP:
10985 {
10986 if (item->is_blocked)
10987 slottype = LOOT_SLOT_TYPE_ROLL_ONGOING;
10988 else if (pLoot->roundRobinPlayer == 0 || !item->is_underthreshold || getGuid() == pLoot->roundRobinPlayer)
10989 slottype = LOOT_SLOT_TYPE_ALLOW_LOOT;
10990 else
10991 // dont show Item.
10992 continue;
10993 }
10994 break;
10996 {
10997 if (!item->is_looted && !item->is_ffa && item->isAllowedForPlayer(this))
10998 {
10999 if (pLoot->roundRobinPlayer != 0 && getGuid() != pLoot->roundRobinPlayer)
11000 // dont show Item.
11001 continue;
11002 }
11003 }
11004 break;
11005 default:
11006 slottype = LOOT_SLOT_TYPE_ALLOW_LOOT;
11007 break;
11008 }
11009 }
11010
11011 data << uint8_t(nonpersonalItemsCount);
11012 data << uint32_t(item->itemproto->ItemId);
11013 data << uint32_t(item->count); //nr of items of this type
11014 data << uint32_t(item->itemproto->DisplayInfoID);
11015
11016 if (item->iRandomSuffix)
11017 {
11018 data << uint32_t(Item::generateRandomSuffixFactor(item->itemproto));
11019 data << uint32_t(-int32_t(item->iRandomSuffix->id));
11020 }
11021 else if (item->iRandomProperty)
11022 {
11023 data << uint32_t(0);
11024 data << uint32_t(item->iRandomProperty->ID);
11025 }
11026 else
11027 {
11028 data << uint32_t(0);
11029 data << uint32_t(0);
11030 }
11031
11032 data << slottype; // "still being rolled for" flag
11033
11034 maxItemsCount++;
11035 }
11036
11037 uint32_t personalItemsCount = maxItemsCount;
11038
11039 // Quest Loot
11040 PersonaltemMap const& lootPlayerQuestItems = pLoot->getPlayerQuestItems();
11041 PersonaltemMap::const_iterator q_itr = lootPlayerQuestItems.find(getGuidLow());
11042 if (q_itr != lootPlayerQuestItems.end())
11043 {
11044 const auto& q_list = q_itr->second;
11045 for (auto qi = q_list->cbegin(); qi != q_list->cend(); ++qi, personalItemsCount++)
11046 {
11048
11049 LootItem& questItem = pLoot->quest_items[qi->index];
11050 if (!qi->is_looted && !questItem.is_looted && questItem.isAllowedForPlayer(this))
11051 {
11052 data << uint8_t(pLoot->items.size() + (qi - q_list->cbegin()));
11053 data << uint32_t(questItem.itemproto->ItemId);
11054 data << uint32_t(questItem.count); //nr of items of this type
11055 data << uint32_t(questItem.itemproto->DisplayInfoID);
11056
11057 if (questItem.iRandomSuffix)
11058 {
11060 data << uint32_t(-int32_t(questItem.iRandomSuffix->id));
11061 }
11062 else if (questItem.iRandomProperty)
11063 {
11064 data << uint32_t(0);
11065 data << uint32_t(questItem.iRandomProperty->ID);
11066 }
11067 else
11068 {
11069 data << uint32_t(0);
11070 data << uint32_t(0);
11071 }
11072
11073 data << slottype; // "still being rolled for" flag
11074 }
11075 maxItemsCount++;
11076 }
11077 }
11078
11079 uint32_t ffaItemsCount = maxItemsCount;
11080
11081 // Free for All
11082 PersonaltemMap const& lootPlayerFFAItems = pLoot->getPlayerFFAItems();
11083 PersonaltemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(getGuidLow());
11084 if (ffa_itr != lootPlayerFFAItems.end())
11085 {
11086 const auto& ffa_list = ffa_itr->second;
11087 for (auto fi = ffa_list->cbegin(); fi != ffa_list->cend(); ++fi, ffaItemsCount++)
11088 {
11090
11091 LootItem& ffaItem = pLoot->items[fi->index];
11092 if (!fi->is_looted && !ffaItem.is_looted && ffaItem.isAllowedForPlayer(this))
11093 {
11094 data << uint8_t(fi->index);
11095 data << uint32_t(ffaItem.itemproto->ItemId);
11096 data << uint32_t(ffaItem.count); //nr of items of this type
11097 data << uint32_t(ffaItem.itemproto->DisplayInfoID);
11098
11099 if (ffaItem.iRandomSuffix)
11100 {
11102 data << uint32_t(-int32_t(ffaItem.iRandomSuffix->id));
11103 }
11104 else if (ffaItem.iRandomProperty)
11105 {
11106 data << uint32_t(0);
11107 data << uint32_t(ffaItem.iRandomProperty->ID);
11108 }
11109 else
11110 {
11111 data << uint32_t(0);
11112 data << uint32_t(0);
11113 }
11114
11115 data << slottype; // "still being rolled for" flag
11116 }
11117 maxItemsCount++;
11118 }
11119 }
11120
11121 data.wpos(13);
11122 data << uint8_t(maxItemsCount);
11123
11124 m_session->SendPacket(&data);
11125
11127}
11128
11130{
11131 if (!isVisibleObject(object->getGuid()))
11132 return;
11133
11134 if (object->isCreatureOrPlayer())
11135 {
11136 // Build the actual update.
11137 ByteBuffer buffer(500);
11138
11139 uint32_t flags = dynamic_cast<Unit*>(object)->getDynamicFlags();
11140
11141 flags |= U_DYN_FLAG_LOOTABLE;
11143
11144#if VERSION_STRING < Mop
11145 object->BuildFieldUpdatePacket(&buffer, getOffsetForStructuredField(WoWUnit, dynamic_flags), flags);
11146#else
11147 object->BuildFieldUpdatePacket(&buffer, getOffsetForStructuredField(WoWObject, dynamic_field), flags);
11148#endif
11149
11151 }
11152}
11153
11155{
11156 WorldPacket data(SMSG_LOOT_LIST, 8 + 1 + 1);
11157 data << uint64_t(creature->getGuid());
11158 data << uint8_t(0); // unk1
11159 data << uint8_t(0); // no group looter
11160 sendMessageToSet(&data, true);
11161}
11162
11164{
11165 Personaltem* questItem = nullptr;
11166 Personaltem* ffaItem = nullptr;
11167
11168 // Pick our loot from Loot Store
11169 LootItem* item = _loot->lootItemInSlot(slot, this, &questItem, &ffaItem);
11170
11171 if (!item)
11172 {
11174 return nullptr;
11175 }
11176
11177 // questitems use the blocked field for other purposes
11178 if (!questItem && item->is_blocked)
11179 {
11180 sendPacket(SmsgLootReleaseResponse(getLootGuid(), 1).serialise().get());
11181 return nullptr;
11182 }
11183
11184 // Add our Item
11185 Item* newItem = storeItem(item);
11186 if (!newItem)
11187 return nullptr;
11188
11189 if (questItem)
11190 {
11191 questItem->is_looted = true;
11192 //freeforall is 1 if everyone's supposed to get the quest item.
11193 if (item->is_ffa || _loot->getPlayerQuestItems().size() == 1)
11194 getSession()->SendPacket(SmsgLootRemoved(slot).serialise().get());
11195 else
11196 _loot->itemRemoved(questItem->index);
11197 }
11198 else
11199 {
11200 if (ffaItem)
11201 {
11202 //freeforall case, notify only one player of the removal
11203 ffaItem->is_looted = true;
11204 getSession()->SendPacket(SmsgLootRemoved(slot).serialise().get());
11205 }
11206 else
11207 {
11208 _loot->itemRemoved(slot);
11209 }
11210 }
11211
11212 //if only one person is supposed to loot the item, then set it to looted
11213 if (!item->is_ffa)
11214 item->is_looted = true;
11215
11216 --_loot->unlootedCount;
11217
11218 return newItem;
11219}
11220
11222{
11223 auto add = getItemInterface()->FindItemLessMax(lootItem->itemId, lootItem->count, false);
11224
11225 // Can we Store our New item?
11226 if (const uint8_t error = getItemInterface()->CanReceiveItem(lootItem->itemproto, lootItem->count) && !add)
11227 {
11228 getItemInterface()->buildInventoryChangeError(nullptr, nullptr, error, lootItem->itemId);
11229 return nullptr;
11230 }
11231
11232 const auto slotResult = getItemInterface()->FindFreeInventorySlot(lootItem->itemproto);
11233 if (!slotResult.Result && !add)
11234 {
11236 return nullptr;
11237 }
11238
11239 // Players which should be able to receive the item after its looted while tradeable
11240 LooterSet looters = lootItem->getAllowedLooters();
11241
11242 if (add == nullptr)
11243 {
11244 // Create the Item
11245 auto newItemHolder = sObjectMgr.createItem(lootItem->itemId, this);
11246 if (newItemHolder == nullptr)
11247 return nullptr;
11248
11249 auto* newItem = newItemHolder.get();
11250 newItem->setStackCount(lootItem->count);
11251 newItem->setOwnerGuid(getGuid());
11252
11253 if (lootItem->iRandomProperty != nullptr)
11254 {
11255 newItem->setRandomPropertiesId(lootItem->iRandomProperty->ID);
11256 newItem->applyRandomProperties(false);
11257 }
11258 else if (lootItem->iRandomSuffix != nullptr)
11259 {
11260 newItem->setRandomSuffix(lootItem->iRandomSuffix->id);
11261 newItem->applyRandomProperties(false);
11262 }
11263
11264 const auto [addResult, _] = getItemInterface()->SafeAddItem(std::move(newItemHolder), slotResult.ContainerSlot, slotResult.Slot);
11265 if (addResult)
11266 {
11267 sendItemPushResultPacket(false, true, true, slotResult.ContainerSlot, slotResult.Slot, lootItem->count, newItem->getEntry(), newItem->getPropertySeed(), newItem->getRandomPropertiesId(), newItem->getStackCount());
11268 sQuestMgr.OnPlayerItemPickup(this, newItem);
11269#if VERSION_STRING > TBC
11270 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, newItem->getEntry(), lootItem->count, 0);
11271 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, newItem->getEntry(), lootItem->count, 0);
11272 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, newItem->getEntry(), lootItem->count);
11273#endif
11274 }
11275 else
11276 {
11277 return nullptr;
11278 }
11279
11280#if VERSION_STRING >= WotLK
11281 // Soulbound Tradeable
11282 if (looters.size() > 1 && lootItem->itemproto->MaxCount == 1 && newItem->isSoulbound())
11283 {
11284 newItem->setSoulboundTradeable(looters);
11285
11286 uint32_t* played = getPlayedTime();
11287 newItem->setCreatePlayedTime(played[1]);
11289 }
11290#endif
11291
11292 return newItem;
11293 }
11294 else
11295 {
11296 add->setStackCount(add->getStackCount() + lootItem->count);
11297 add->m_isDirty = true;
11298 add->setOwnerGuid(getGuid());
11299
11300 sendItemPushResultPacket(false, true, true, slotResult.ContainerSlot, slotResult.Slot, lootItem->count, add->getEntry(), add->getPropertySeed(), add->getRandomPropertiesId(), add->getStackCount());
11301 sQuestMgr.OnPlayerItemPickup(this, add);
11302#if VERSION_STRING > TBC
11303 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, add->getEntry(), 1, 0);
11304#endif
11305 return add;
11306 }
11307}
11308
11310void Player::setLootableOnCorpse(bool lootable) { m_lootableOnCorpse = lootable; }
11311
11312/////////////////////////////////////////////////////////////////////////////////////////
11313// Reputation
11314inline bool CanToggleAtWar(uint8_t flag) { return (flag & FACTION_FLAG_DISABLE_ATWAR) == 0; }
11315inline bool AtWar(uint8_t flag) { return (flag & FACTION_FLAG_AT_WAR) != 0; }
11316inline bool ForcedInvisible(uint8_t flag) { return (flag & FACTION_FLAG_FORCED_INVISIBLE) != 0; }
11317inline bool Visible(uint8_t flag) { return (flag & FACTION_FLAG_VISIBLE) != 0; }
11318inline bool Hidden(uint8_t flag) { return (flag & FACTION_FLAG_HIDDEN) != 0; }
11319inline bool Inactive(uint8_t flag) { return (flag & FACTION_FLAG_INACTIVE) != 0; }
11320
11321inline bool SetFlagAtWar(uint8_t& flag, bool set)
11322{
11323 if (set && !AtWar(flag))
11324 flag |= FACTION_FLAG_AT_WAR;
11325 else if (!set && AtWar(flag))
11326 flag &= ~FACTION_FLAG_AT_WAR;
11327 else
11328 return false;
11329
11330 return true;
11331}
11332
11333inline bool SetFlagVisible(uint8_t& flag, bool set)
11334{
11335 if (ForcedInvisible(flag) || Hidden(flag))
11336 return false;
11337 else if (set && !Visible(flag))
11338 flag |= FACTION_FLAG_VISIBLE;
11339 else if (!set && Visible(flag))
11340 flag &= ~FACTION_FLAG_VISIBLE;
11341 else
11342 return false;
11343
11344 return true;
11345}
11346
11347inline bool SetFlagInactive(uint8_t& flag, bool set)
11348{
11349 if (set && !Inactive(flag))
11350 flag |= FACTION_FLAG_INACTIVE;
11351 else if (!set && Inactive(flag))
11352 flag &= ~FACTION_FLAG_INACTIVE;
11353 else
11354 return false;
11355
11356 return true;
11357}
11358
11363
11368
11370{
11371 WDB::Structures::FactionEntry const* factionEntry = sFactionStore.lookupEntry(faction);
11372 if (!factionEntry || factionEntry->RepListId < 0)
11373 return;
11374
11375 const int32_t minReputation = -42000; // 0/36000 Hated
11376 const int32_t exaltedReputation = 42000; // 0/1000 Exalted
11377 const int32_t maxReputation = 42999; // 999/1000 Exalted
11378
11379 int32_t newValue = value;
11380 if (newValue < minReputation)
11381 newValue = minReputation;
11382 else if (newValue > maxReputation)
11383 newValue = maxReputation;
11384
11385 auto reputation = m_reputation.find(faction);
11386 if (reputation == m_reputation.end())
11387 {
11388 if (!addNewFaction(factionEntry, newValue, false))
11389 return;
11390
11391 reputation = m_reputation.find(faction);
11392
11393#if VERSION_STRING > TBC
11394 if (reputation->second->standing >= 42000)
11395 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, 1, 0, 0);
11396
11397 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID, reputation->second->standing, 0);
11398#endif
11399
11401 onModStanding(factionEntry, reputation->second.get());
11402 }
11403 else
11404 {
11405 if (RankChangedFlat(reputation->second->standing, newValue))
11406 {
11407
11408#if VERSION_STRING > TBC
11409 if (reputation->second->standing - newValue >= exaltedReputation)
11410 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, -1, 0, 0);
11411 else if (newValue >= exaltedReputation)
11412 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, 1, 0, 0);
11413#endif
11414
11415 reputation->second->standing = newValue;
11417
11418#if VERSION_STRING > TBC
11419 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID, value, 0);
11420#endif
11421
11422 }
11423 else
11424 {
11425 reputation->second->standing = newValue;
11426 }
11427
11428 onModStanding(factionEntry, reputation->second.get());
11429 }
11430}
11431
11433{
11434 const ReputationMap::iterator itr = m_reputation.find(faction);
11435 if (itr != m_reputation.end())
11436 return itr->second->standing;
11437 return 0;
11438}
11439
11441{
11442 const ReputationMap::iterator itr = m_reputation.find(faction);
11443 if (itr != m_reputation.end())
11444 return itr->second->baseStanding;
11445 return 0;
11446}
11447
11449{
11450 WDB::Structures::FactionEntry const* factionEntry = sFactionStore.lookupEntry(faction);
11451 if (factionEntry == nullptr || factionEntry->RepListId < 0)
11452 return;
11453
11454 const int32_t minReputation = -42000; // 0/36000 Hated
11455 const int32_t exaltedReputation = 42000; // 0/1000 Exalted
11456 const int32_t maxReputation = 42999; // 999/1000 Exalted
11457
11458 if ((getWorldMap()->getBaseMap()->getMapInfo()->minlevel == 80 ||
11459 (getWorldMap()->getDifficulty() == InstanceDifficulty::DUNGEON_HEROIC && getWorldMap()->getBaseMap()->getMapInfo()->minlevel_heroic == 80)) &&
11461 faction = m_championingFactionId;
11462
11463 int32_t newValue = value;
11464 if (newValue < minReputation)
11465 newValue = minReputation;
11466 else if (newValue > maxReputation)
11467 newValue = maxReputation;
11468
11469 ReputationMap::iterator itr = m_reputation.find(faction);
11470 if (itr == m_reputation.end())
11471 {
11472 if (!addNewFaction(factionEntry, newValue, false))
11473 return;
11474
11475 itr = m_reputation.find(faction);
11476
11477#if VERSION_STRING > TBC
11478 if (itr->second->standing >= 42000)
11479 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, 1, 0, 0);
11480
11481 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID, itr->second->standing, 0);
11482#endif
11483
11485 onModStanding(factionEntry, itr->second.get());
11486 }
11487 else
11488 {
11489 if (m_pctReputationMod > 0)
11490 newValue = value + (value * m_pctReputationMod / 100);
11491
11492 if (RankChanged(itr->second->standing, newValue))
11493 {
11494 itr->second->standing += newValue;
11496
11497#if VERSION_STRING > TBC
11498 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID, itr->second->standing, 0);
11499 if (itr->second->standing >= exaltedReputation)
11500 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, 1, 0, 0);
11501 else if (itr->second->standing - newValue >= exaltedReputation)
11502 updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, -1, 0, 0);
11503#endif
11504
11505 }
11506 else
11507 {
11508 itr->second->standing += newValue;
11509 }
11510
11511 if (itr->second->standing < minReputation)
11512 itr->second->standing = minReputation;
11513 else if (itr->second->standing > maxReputation)
11514 itr->second->standing = maxReputation;
11515 onModStanding(factionEntry, itr->second.get());
11516 }
11517}
11518
11523
11525{
11526 if (value >= 42000)
11527 return STANDING_EXALTED;
11528 if (value >= 21000)
11529 return STANDING_REVERED;
11530 if (value >= 9000)
11531 return STANDING_HONORED;
11532 if (value >= 3000)
11533 return STANDING_FRIENDLY;
11534 if (value >= 0)
11535 return STANDING_NEUTRAL;
11536 if (value > -3000)
11537 return STANDING_UNFRIENDLY;
11538 if (value > -6000)
11539 return STANDING_HOSTILE;
11540
11541 return STANDING_HATED;
11542}
11543
11544void Player::applyForcedReaction(uint32_t faction_id, Standing rank, bool apply)
11545{
11546 if (apply)
11547 m_forcedReactions[faction_id] = rank;
11548 else
11549 m_forcedReactions.erase(faction_id);
11550}
11551
11553{
11554 const auto itr = m_forcedReactions.find(factionTemplateEntry->Faction);
11555 return itr != m_forcedReactions.end() ? &itr->second : nullptr;
11556}
11557
11559{
11560 if (faction >= 128)
11561 return;
11562
11563 FactionReputation* factionReputation = m_reputationByListId[faction];
11564 if (!factionReputation)
11565 return;
11566
11567 if (getReputationRankFromStanding(factionReputation->standing) <= STANDING_HOSTILE && !set)
11568 return;
11569
11570 if (!CanToggleAtWar(factionReputation->flag))
11571 return;
11572
11573 if (SetFlagAtWar(factionReputation->flag, set))
11575}
11576
11578{
11579 if (!factionEntry)
11580 return false;
11581
11582 FactionReputation const* factionState = m_reputationByListId[factionEntry->RepListId];
11583 if (factionState == nullptr)
11584 return false;
11585
11586 return AtWar(factionState->flag);
11587
11588 return false;
11589}
11590
11592{
11593 if (!factionEntry)
11594 return false;
11595
11596 if (factionEntry->RepListId < 0 || factionEntry->RepListId >= 128)
11597 return false;
11598
11599 FactionReputation* factionReputation = m_reputationByListId[factionEntry->RepListId];
11600 if (factionReputation == nullptr)
11601 return false;
11602
11603 const auto itr = m_forcedReactions.find(factionEntry->ID);
11604 if (itr != m_forcedReactions.end())
11605 return itr->second <= STANDING_HOSTILE;
11606
11607 return AtWar(factionReputation->flag) || getReputationRankFromStanding(factionReputation->standing) <= STANDING_HOSTILE;
11608}
11609
11611{
11612 for (const auto& object : getInRangeObjectsSet())
11613 {
11614 if (!object->isCreatureOrPlayer())
11615 continue;
11616
11617 if (const auto unit = dynamic_cast<Unit*>(object))
11618 {
11619 if (unit->m_factionEntry == nullptr || unit->m_factionEntry->RepListId < 0)
11620 continue;
11621
11622 bool isHostile = isHostileBasedOnReputation(unit->m_factionEntry);
11623 bool currentHostileObject = isObjectInInRangeOppositeFactionSet(unit);
11624
11625 if (isHostile && !currentHostileObject)
11627 else if (!isHostile && currentHostileObject)
11629 }
11630 }
11631}
11632
11633void Player::onKillUnitReputation(Unit* unit, bool innerLoop)
11634{
11635 if (!unit)
11636 return;
11637
11638 if (!unit->isCreature() || unit->isPet() || unit->isCritter())
11639 return;
11640
11641 if (auto m_Group = getGroup())
11642 {
11643 if (!innerLoop)
11644 {
11645 m_Group->getLock().lock();
11646
11647 for (uint32_t i = 0; i < m_Group->GetSubGroupCount(); ++i)
11648 for (auto groupMember : m_Group->GetSubGroup(i)->getGroupMembers())
11649 if (auto player = sObjectMgr.getPlayer(groupMember->guid))
11650 if (player->isInRange(this, 100.0f))
11651 player->onKillUnitReputation(unit, true);
11652
11653 m_Group->getLock().unlock();
11654
11655 return;
11656 }
11657 }
11658
11659 const uint32_t team = getTeam();
11660 auto modifier = sObjectMgr.getReputationModifier(unit->getEntry(), unit->m_factionEntry->ID);
11661 if (modifier != nullptr)
11662 {
11663 for (auto& mod : modifier->mods)
11664 {
11665 if (!mod->faction[team])
11666 continue;
11667
11669 if (mod->replimit)
11670 if (getFactionStanding(mod->faction[team]) >= static_cast<int32_t>(mod->replimit))
11671 continue;
11672
11673 modFactionStanding(mod->faction[team], Util::float2int32(mod->value * worldConfig.getFloatRate(RATE_KILLREPUTATION)));
11674 }
11675 }
11676 else
11677 {
11678 if (IS_INSTANCE(GetMapId()) && sObjectMgr.handleInstanceReputationModifiers(this, unit))
11679 return;
11680
11681 if (unit->m_factionEntry->RepListId < 0)
11682 return;
11683
11684 const int32_t change = static_cast<int32_t>(-5.0f * worldConfig.getFloatRate(RATE_KILLREPUTATION));
11685 modFactionStanding(unit->m_factionEntry->ID, change);
11686 }
11687}
11688
11690{
11691 if (!factionEntry || factionEntry->RepListId < 0)
11692 return;
11693
11694 FactionReputation* factionReputation = m_reputationByListId[factionEntry->RepListId];
11695 if (factionReputation == nullptr)
11696 return;
11697
11698 if (SetFlagVisible(factionReputation->flag, true) && IsInWorld())
11699 sendPacket(SmsgSetFactionVisible(factionEntry->RepListId).serialise().get());
11700}
11701
11702void Player::setFactionInactive(uint32_t faction, bool /*set*/)
11703{
11704 FactionReputation* factionReputation = m_reputationByListId[faction];
11705 if (!factionReputation)
11706 return;
11707}
11708
11709bool Player::addNewFaction(WDB::Structures::FactionEntry const* factionEntry, int32_t standing, bool base)
11710{
11711 if (!factionEntry || factionEntry->RepListId < 0)
11712 return false;
11713
11714 for (uint8_t i = 0; i < 4; ++i)
11715 {
11716 if ((factionEntry->RaceMask[i] & getRaceMask() ||
11717 factionEntry->RaceMask[i] == 0 && factionEntry->ClassMask[i] != 0) &&
11718 (factionEntry->ClassMask[i] & getClassMask() || factionEntry->ClassMask[i] == 0))
11719 {
11720 const auto flag = static_cast<uint8_t>(factionEntry->repFlags[i]);
11721 const auto baseStanding = factionEntry->baseRepValue[i];
11722 const auto m_standing = (base) ? factionEntry->baseRepValue[i] : standing;
11723
11724 const auto [repItr, _] = m_reputation.insert_or_assign(factionEntry->ID, std::make_unique<FactionReputation>(m_standing, flag, baseStanding));
11725 m_reputationByListId[factionEntry->RepListId] = repItr->second.get();
11726
11727 return true;
11728 }
11729 }
11730 return false;
11731}
11732
11734{
11735 if (!factionEntry || !reputation)
11736 return;
11737
11738 if (SetFlagVisible(reputation->flag, true) && IsInWorld())
11739 sendPacket(SmsgSetFactionVisible(factionEntry->RepListId).serialise().get());
11740
11742
11743 if (Visible(reputation->flag) && IsInWorld())
11744 sendPacket(SmsgSetFactionStanding(factionEntry->RepListId, reputation->CalcStanding()).serialise().get());
11745}
11746
11748{
11749 uint32_t exaltedCount = 0;
11750
11751 auto itr = m_reputation.begin();
11752 while (itr != m_reputation.end())
11753 {
11754 const int32_t exaltedReputation = 42000;
11755 if (itr->second->standing >= exaltedReputation)
11756 ++exaltedCount;
11757 ++itr;
11758 }
11759 return exaltedCount;
11760}
11761
11763{
11764#if VERSION_STRING == Mop
11765 const uint16_t factionCount = 256;
11767 uint32_t a = 0;
11768
11769 WorldPacket data(SMSG_INITIALIZE_FACTIONS, factionCount * (1 + 4) + 32);
11770 for (; a != factionCount; ++a)
11771 {
11772 data << uint8_t(0);
11773 data << uint32_t(0);
11774 buffer.writeBit(0);
11775 }
11776
11777 buffer.flushBits();
11778
11779 data.append(buffer);
11780#else
11782 data << uint32_t(128);
11783
11784 for (auto& i : m_reputationByListId)
11785 {
11786 FactionReputation* factionReputation = i;
11787 if (!factionReputation)
11788 {
11789 data << uint8_t(0);
11790 data << uint32_t(0);
11791 }
11792 else
11793 {
11794 data << factionReputation->flag;
11795 data << factionReputation->CalcStanding();
11796 }
11797 }
11798
11799#endif
11800 m_session->SendPacket(&data);
11801}
11802
11804{
11805 for (uint32_t i = 0; i < sFactionStore.getNumRows(); ++i)
11806 {
11807 WDB::Structures::FactionEntry const* factionEntry = sFactionStore.lookupEntry(i);
11808 addNewFaction(factionEntry, 0, true);
11809 }
11810}
11811
11813{
11814 if (const auto raceEntry = sChrRacesStore.lookupEntry(getRace()))
11815 return raceEntry->faction_id;
11816
11817 return 0;
11818}
11819
11822
11824
11825/////////////////////////////////////////////////////////////////////////////////////////
11826// Drunk system
11828
11830{
11831 const uint32_t oldDrunkenState = getDrunkStateByValue(m_serversideDrunkValue);
11832
11833 m_serversideDrunkValue = newDrunkenValue;
11835
11836 const uint32_t newDrunkenState = getDrunkStateByValue(m_serversideDrunkValue);
11837
11838 if (newDrunkenState == oldDrunkenState)
11839 return;
11840
11841 if (newDrunkenState >= DRUNKEN_DRUNK)
11843 else
11845
11847
11848 sendNewDrunkStatePacket(newDrunkenState, itemId);
11849}
11850
11852{
11853 if (value >= 23000)
11854 return DRUNKEN_SMASHED;
11855
11856 if (value >= 12800)
11857 return DRUNKEN_DRUNK;
11858
11859 if (value & 0xFFFE)
11860 return DRUNKEN_TIPSY;
11861
11862 return DRUNKEN_SOBER;
11863}
11864
11866{
11867 m_drunkTimer = 0;
11868
11869 setDrunkValue((m_serversideDrunkValue <= 256) ? 0U : static_cast<uint8_t>(m_serversideDrunkValue - 256));
11870}
11871
11872/////////////////////////////////////////////////////////////////////////////////////////
11873// Duel
11876{
11877 if (m_duelPlayer != nullptr)
11878 return;
11879
11881 return;
11882
11884
11885 target->m_duelPlayer = this;
11886 m_duelPlayer = target;
11887
11888 // flag position
11889 const float distance = CalcDistance(target) * 0.5f;
11890 const float x = (GetPositionX() + target->GetPositionX() * distance) / (1 + distance) + cos(GetOrientation() + (M_PI_FLOAT / 2)) * 2;
11891 const float y = (GetPositionY() + target->GetPositionY() * distance) / (1 + distance) + sin(GetOrientation() + (M_PI_FLOAT / 2)) * 2;
11892 const float z = (GetPositionZ() + target->GetPositionZ() * distance) / (1 + distance);
11893
11894 // create flag
11895 if (GameObject* goFlag = getWorldMap()->createGameObject(21680))
11896 {
11897 goFlag->create(21680, m_WorldMap, GetPhase(), LocationVector(x, y, z, GetOrientation()), QuaternionData(), GO_STATE_CLOSED);
11898
11899 goFlag->setCreatedByGuid(getGuid());
11900 goFlag->SetFaction(getFactionTemplate());
11901 goFlag->setLevel(getLevel());
11902
11903 setDuelArbiter(goFlag->getGuid());
11904 target->setDuelArbiter(goFlag->getGuid());
11905
11906 goFlag->PushToWorld(m_WorldMap);
11907
11908 addGameObject(goFlag);
11909
11910 target->getSession()->SendPacket(SmsgDuelRequested(goFlag->getGuid(), getGuid()).serialise().get());
11911 }
11912}
11913
11915{
11916 if (!IsInWorld())
11917 return;
11918
11919 WoWGuid wowGuid;
11920 wowGuid.Init(getDuelArbiter());
11921
11922 if (GameObject* goFlag = getWorldMap()->getGameObject(wowGuid.getGuidLowPart()))
11923 {
11924 if (CalcDistance(goFlag) > 75.0f)
11925 {
11927 {
11928 m_duelCountdownTimer -= 500;
11929 if (m_duelCountdownTimer == 0)
11931 }
11932 else
11933 {
11934 m_duelCountdownTimer = 10000;
11935
11938 }
11939 }
11940 else
11941 {
11943 {
11944 sendPacket(SmsgDuelInbounds().serialise().get());
11946 }
11947 }
11948 }
11949 else
11950 {
11952 }
11953}
11954
11956{
11957 WoWGuid wowGuid;
11958 wowGuid.Init(getDuelArbiter());
11959
11961 {
11962 if (wowGuid.getGuidLowPart())
11963 {
11964 GameObject* arbiter = m_WorldMap ? getWorldMap()->getGameObject(wowGuid.getGuidLowPart()) : nullptr;
11965 if (arbiter)
11966 {
11967 arbiter->RemoveFromWorld(true);
11968 delete arbiter;
11969 }
11970
11972 setDuelArbiter(0);
11973
11975 setDuelTeam(0);
11976
11979
11980 m_duelPlayer->m_duelPlayer = nullptr;
11981 m_duelPlayer = nullptr;
11982 }
11983
11984 return;
11985 }
11986
11987 sEventMgr.RemoveEvents(this, EVENT_PLAYER_DUEL_COUNTDOWN);
11988 sEventMgr.RemoveEvents(this, EVENT_PLAYER_DUEL_BOUNDARY_CHECK);
11989
11991 {
11992 auto* const aur = getAuraWithAuraSlot(x);
11993 if (aur == nullptr)
11994 continue;
11995
11996 if (aur->WasCastInDuel())
11997 aur->removeAura();
11998 }
11999
12001
12002 if (m_duelPlayer == nullptr)
12003 return;
12004
12007
12009 {
12010 auto* const aur = m_duelPlayer->getAuraWithAuraSlot(x);
12011 if (aur == nullptr)
12012 continue;
12013 if (aur->WasCastInDuel())
12014 aur->removeAura();
12015 }
12016
12018
12019 sendMessageToSet(SmsgDuelWinner(condition, getName(), m_duelPlayer->getName()).serialise().get(), true);
12020 sendMessageToSet(SmsgDuelComplete(1).serialise().get(), true);
12021
12022 if (condition != 0)
12023 sHookInterface.OnDuelFinished(m_duelPlayer, this);
12024 else
12025 sHookInterface.OnDuelFinished(this, m_duelPlayer);
12026
12027 GameObject* goFlag = m_WorldMap ? getWorldMap()->getGameObject(wowGuid.getGuidLowPart()) : nullptr;
12028 if (goFlag)
12029 {
12030 goFlag->RemoveFromWorld(true);
12031 delete goFlag;
12032 }
12033
12034 setDuelArbiter(0);
12036
12037 setDuelTeam(0);
12039
12042
12043 for (auto& summon : getSummonInterface()->getSummons())
12044 {
12045 summon->getCombatHandler().clearCombat();
12046 summon->getAIInterface()->setPetOwner(this);
12047 summon->getAIInterface()->handleEvent(EVENT_FOLLOWOWNER, summon, 0);
12048 summon->getThreatManager().clearAllThreat();
12049 summon->getThreatManager().removeMeFromThreatLists();
12050 }
12051
12052 for (auto& duelingWithSummon : m_duelPlayer->getSummonInterface()->getSummons())
12053 {
12054 duelingWithSummon->getCombatHandler().clearCombat();
12055 duelingWithSummon->getAIInterface()->setPetOwner(this);
12056 duelingWithSummon->getAIInterface()->handleEvent(EVENT_FOLLOWOWNER, duelingWithSummon, 0);
12057 duelingWithSummon->getThreatManager().clearAllThreat();
12058 duelingWithSummon->getThreatManager().removeMeFromThreatLists();
12059 }
12060
12063
12066
12069
12070 m_duelPlayer->m_duelPlayer = nullptr;
12071 m_duelPlayer = nullptr;
12072}
12073
12075{
12076 WoWGuid wowGuid;
12077 wowGuid.Init(getDuelArbiter());
12078
12079 const auto goFlag = getWorldMap()->getGameObject(wowGuid.getGuidLowPart());
12080 if (goFlag)
12081 goFlag->RemoveFromWorld(true);
12082
12083 setDuelArbiter(0);
12085
12088
12090 setDuelTeam(0);
12091
12094
12095 m_duelPlayer->m_duelPlayer = nullptr;
12096 m_duelPlayer = nullptr;
12097}
12098
12124
12127
12130
12131/////////////////////////////////////////////////////////////////////////////////////////
12132// Resting/Experience XP
12133void Player::giveXp(uint32_t xp, const uint64_t& guid, bool allowBonus)
12134{
12135 if (xp < 1)
12136 return;
12137
12138#if VERSION_STRING >= Cata
12139 //this is new since 403. As we gain XP we also gain XP with our guild
12141 {
12142 uint32_t guild_share = xp / 100;
12143
12144 if (Guild* guild = sGuildMgr.getGuildById(m_playerInfo->m_guild))
12145 guild->giveXP(guild_share, this);
12146 }
12147#endif
12148
12149 if (!m_isXpGainAllowed)
12150 return;
12151
12152 if (getLevel() >= getMaxLevel())
12153 return;
12154
12155 uint32_t restXp = xp;
12156
12157 if (m_restState == RESTSTATE_RESTED && allowBonus)
12158 {
12159 restXp = subtractRestXp(xp);
12160 xp += restXp;
12161 }
12162
12164
12165 sendLogXpGainPacket(guid, xp, restXp, guid == 0 ? true : false);
12166
12167 int32_t newXp = getXp() + xp;
12168 int32_t nextLevelXp = getNextLevelXp();
12169 uint32_t level = getLevel();
12170 bool levelup = false;
12171
12172 while (newXp >= nextLevelXp && newXp > 0)
12173 {
12174 ++level;
12175 if (sObjectMgr.getLevelInfo(getRace(), getClass(), level))
12176 {
12177 newXp -= nextLevelXp;
12178 nextLevelXp = sMySQLStore.getPlayerXPForLevel(level);
12179 levelup = true;
12180 if (level >= getMaxLevel())
12181 break;
12182 }
12183 else
12184 {
12185 return;
12186 }
12187 }
12188
12189 if (level > getMaxLevel())
12190 level = getMaxLevel();
12191
12192 if (levelup)
12193 applyLevelInfo(level);
12194
12195 setXp(newXp);
12196}
12197
12198void Player::sendLogXpGainPacket(uint64_t guid, uint32_t normalXp, uint32_t restedXp, bool type)
12199{
12200 m_session->SendPacket(SmsgLogXpGain(guid, normalXp, restedXp, type).serialise().get());
12201}
12202
12204bool Player::canGainXp() const { return m_isXpGainAllowed; }
12205
12207{
12208 if (getLevel() >= getMaxLevel())
12209 amount = 0;
12210
12211 const int32_t restAmount = m_restAmount - (amount << 1);
12212 if (restAmount < 0)
12213 m_restAmount = 0;
12214 else
12215 m_restAmount = restAmount;
12216
12217 sLogger.debug("Subtracted {} rest XP to a total of {}", amount, m_restAmount);
12218
12220
12221 return amount;
12222}
12223
12225{
12226 const uint32_t nextLevelXp = getNextLevelXp();
12227
12228 const float restXpRate = worldConfig.getFloatRate(RATE_RESTXP);
12229
12230 auto restXp = static_cast<uint32_t>(0.05f * nextLevelXp * (seconds / (3600 * (8 / restXpRate))));
12231
12232 if (m_isResting)
12233 restXp <<= 2;
12234
12235 m_restAmount += restXp;
12236
12237 if (m_restAmount > nextLevelXp + static_cast<uint32_t>(static_cast<float>(nextLevelXp >> 1) * restXpRate))
12238 m_restAmount = nextLevelXp + static_cast<uint32_t>(static_cast<float>(nextLevelXp >> 1) * restXpRate);
12239
12240 sLogger.debug("Add {} rest XP to a total of {}, RestState {}", restXp, m_restAmount, m_isResting);
12241
12243}
12244
12246{
12247 if (apply)
12248 {
12250 m_isResting = true;
12252 }
12253 else
12254 {
12255 m_isResting = false;
12257 }
12258
12260}
12261
12263{
12264 if (m_restAmount && getLevel() < getMaxLevel())
12266 else
12268
12271}
12272
12273/////////////////////////////////////////////////////////////////////////////////////////
12274// Pets/Summons
12275
12277{
12278 const auto itr = m_cachedPets.find(petId);
12279 if (itr != m_cachedPets.cend())
12280 return itr->second.get();
12281
12282 return nullptr;
12283}
12284
12286{
12287 const auto itr = m_cachedPets.find(petId);
12288 if (itr != m_cachedPets.cend())
12289 return itr->second.get();
12290
12291 return nullptr;
12292}
12293
12295{
12296 return m_cachedPets;
12297}
12298
12299std::map<uint8_t, uint8_t> const& Player::getPetCachedSlotMap() const
12300{
12301 return m_cachedPetSlots;
12302}
12303
12304void Player::addPetCache(std::unique_ptr<PetCache> pet, uint8_t index)
12305{
12306 m_cachedPetSlots.emplace(pet->slot, index);
12307 m_cachedPets.emplace(index, std::move(pet));
12308}
12309
12311{
12312 const auto itr = std::as_const(m_cachedPets).find(petId);
12313 if (itr != m_cachedPets.cend())
12314 {
12315 std::erase_if(m_cachedPetSlots, [petId](const auto& slotItr) { return slotItr.second == petId; });
12316 m_cachedPets.erase(itr);
12317 }
12318
12319 // Pet will be deleted from playerpets table when player is saved
12320 CharacterDatabase.Execute("DELETE FROM playerpetspells WHERE ownerguid=%u AND petnumber=%u", getGuidLow(), petId);
12321}
12322
12323uint8_t Player::getPetCount() const { return static_cast<uint8_t>(m_cachedPets.size()); }
12324
12326{
12327 for (uint8_t i = 1; i < m_maxPetNumber; ++i)
12328 if (!m_cachedPets.contains(i))
12329 return i;
12330
12331 m_maxPetNumber += 1;
12332 return m_maxPetNumber;
12333}
12334
12335std::optional<uint8_t> Player::getPetIdFromSlot(uint8_t slot) const
12336{
12337 const auto itr = m_cachedPetSlots.find(slot);
12338 if (itr != m_cachedPetSlots.cend())
12339 return itr->second;
12340
12341 return std::nullopt;
12342}
12343
12345{
12346 return m_cachedPetSlots.contains(slot);
12347}
12348
12349std::optional<uint8_t> Player::findFreeActivePetSlot() const
12350{
12351 std::optional<uint8_t> foundSlot = std::nullopt;
12353 {
12354 if (!hasPetInSlot(i))
12355 {
12356 foundSlot = i;
12357 break;
12358 }
12359 }
12360 return foundSlot;
12361}
12362
12363std::optional<uint8_t> Player::findFreeStablePetSlot() const
12364{
12365 std::optional<uint8_t> foundSlot = std::nullopt;
12367 {
12369 break;
12370
12371 if (!hasPetInSlot(i))
12372 {
12373 foundSlot = i;
12374 break;
12375 }
12376 }
12377 return foundSlot;
12378}
12379
12380bool Player::tryPutPetToSlot(uint8_t petId, uint8_t newSlot, bool sendErrors/* = true*/)
12381{
12382 const auto petItr = std::as_const(m_cachedPets).find(petId);
12383 if (petItr == m_cachedPets.cend())
12384 {
12385 if (sendErrors)
12387
12388 return false;
12389 }
12390
12391 // Check if pet is being tried to move to same slot where it is already
12392 if (petItr->second->slot == newSlot)
12393 {
12394 if (sendErrors)
12396
12397 return false;
12398 }
12399
12400 auto* oldSlotPet = petItr->second.get();
12401 // Pet that possibly exists in new slot
12402 PetCache* newSlotPet = nullptr;
12403
12404 const auto slotItr = std::as_const(m_cachedPetSlots).find(newSlot);
12405 if (slotItr != m_cachedPetSlots.cend())
12406 {
12407 const auto existingPetItr = std::as_const(m_cachedPets).find(slotItr->second);
12408 if (existingPetItr != m_cachedPets.cend())
12409 newSlotPet = existingPetItr->second.get();
12410 }
12411
12412 const auto isOldSlotActiveSlot = oldSlotPet->slot < PET_SLOT_MAX_ACTIVE_SLOT;
12413 const auto isNewSlotActiveSlot = newSlot < PET_SLOT_MAX_ACTIVE_SLOT;
12414
12415#if VERSION_STRING >= WotLK
12416 if (isNewSlotActiveSlot)
12417 {
12418 // Check if player can have exotic pets when taking pet from stables
12419 if (const auto creatureProperties = sMySQLStore.getCreatureProperties(oldSlotPet->entry))
12420 {
12421 if (creatureProperties->isExotic() && !hasAuraWithAuraEffect(SPELL_AURA_ALLOW_TAME_PET_TYPE))
12422 {
12423 if (sendErrors)
12425
12426 return false;
12427 }
12428 }
12429 }
12430
12431 if (isOldSlotActiveSlot && !isNewSlotActiveSlot && newSlotPet != nullptr)
12432 {
12433 // Check also if pet in new slot is exotic if player is swapping pet slots
12434 if (const auto creatureProperties = sMySQLStore.getCreatureProperties(newSlotPet->entry))
12435 {
12436 if (creatureProperties->isExotic() && !hasAuraWithAuraEffect(SPELL_AURA_ALLOW_TAME_PET_TYPE))
12437 {
12438 if (sendErrors)
12440
12441 return false;
12442 }
12443 }
12444 }
12445#endif
12446
12447 if (!isNewSlotActiveSlot)
12448 {
12449 // Must be hunter pet
12450 if (oldSlotPet->type != PET_TYPE_HUNTER)
12451 {
12452 if (sendErrors)
12454
12455 return false;
12456 }
12457 }
12458
12459 m_cachedPetSlots.insert_or_assign(newSlot, petId);
12460 if (newSlotPet != nullptr)
12461 m_cachedPetSlots.insert_or_assign(oldSlotPet->slot, newSlotPet->number);
12462 else
12463 m_cachedPetSlots.erase(oldSlotPet->slot);
12464
12465 // Update only slot in pet cache, full update is done in possible summon/unsummon
12466 if (newSlotPet != nullptr)
12467 newSlotPet->slot = oldSlotPet->slot;
12468 oldSlotPet->slot = newSlot;
12469
12470 auto requiresPetSave = false;
12471 if (isOldSlotActiveSlot && !isNewSlotActiveSlot)
12472 {
12473 // Active pet is put to stables
12474 auto* const currentPet = getPet();
12475 if (currentPet != nullptr && currentPet->getPetId() == petId)
12476 {
12477 currentPet->unSummon();
12478 if (newSlotPet != nullptr && !isPetRequiringTemporaryUnsummon() && newSlotPet->alive)
12479 _spawnPet(newSlotPet);
12480 }
12481 else
12482 {
12483 // If this pet was temporary unsummoned make the other pet active as well
12484 if (newSlotPet != nullptr)
12485 newSlotPet->active = oldSlotPet->active;
12486 oldSlotPet->active = false;
12487 requiresPetSave = true;
12488 }
12489 }
12490 else if (!isOldSlotActiveSlot && isNewSlotActiveSlot)
12491 {
12492 // Pet is taken from stables
12493 if (newSlotPet != nullptr)
12494 {
12495 auto* const currentPet = getPet();
12496 // Only summon it if it's put to same slot as current summoned pet
12497 if (currentPet != nullptr && currentPet->getPetId() == newSlotPet->number)
12498 {
12499 currentPet->unSummon();
12500 if (!isPetRequiringTemporaryUnsummon() && oldSlotPet->alive)
12501 _spawnPet(oldSlotPet);
12502 }
12503 else
12504 {
12505 // If pet from new slot was temporary unsummoned make this pet active as well
12506 oldSlotPet->active = newSlotPet->active;
12507 newSlotPet->active = false;
12508 requiresPetSave = true;
12509 }
12510 }
12511 else
12512 {
12513 requiresPetSave = true;
12514 }
12515 }
12516 else if ((!isOldSlotActiveSlot && !isNewSlotActiveSlot) || (isOldSlotActiveSlot && isNewSlotActiveSlot))
12517 {
12518 // Pet is either moved inside stables or its active slot was changed
12519 // In either case unsummon is not required, just save pets to database
12520 requiresPetSave = true;
12521 }
12522
12523 if (requiresPetSave)
12524 {
12525 // Save only slot and active fields
12526 CharacterDatabase.Execute("UPDATE playerpets SET slot = %u, active = %u WHERE ownerguid = %u AND petnumber = %u",
12527 oldSlotPet->slot, oldSlotPet->active, getGuidLow(), oldSlotPet->number);
12528 if (newSlotPet != nullptr)
12529 {
12530 CharacterDatabase.Execute("UPDATE playerpets SET slot = %u, active = %u WHERE ownerguid = %u AND petnumber = %u",
12531 newSlotPet->slot, newSlotPet->active, getGuidLow(), newSlotPet->number);
12532 }
12533 }
12534
12535 return true;
12536}
12537
12539{
12540 const auto itr = m_cachedPets.find(petId);
12541 if (itr == m_cachedPets.cend())
12542 {
12543 sLogger.failure("Player::spawnPet : {} tried to load invalid pet {}", std::to_string(getGuid()), petId);
12544 return;
12545 }
12546
12547 if (itr->second.get()->slot >= PET_SLOT_MAX_ACTIVE_SLOT)
12548 {
12549 sLogger.debug("Player::spawnPet : {} tried to spawn pet from stable slot {}", std::to_string(getGuid()), std::to_string(itr->second.get()->slot));
12550 return;
12551 }
12552
12553 _spawnPet(itr->second.get());
12554}
12555
12557{
12558 if (getPet() != nullptr)
12559 return;
12560
12562 return;
12563
12564 for (const auto& [slot, petId] : std::as_const(m_cachedPetSlots))
12565 {
12566 // Just check active slots
12567 if (slot >= PET_SLOT_MAX_ACTIVE_SLOT)
12568 break;
12569
12570 auto* const petCache = getModifiablePetCache(petId);
12571 if (petCache != nullptr && petCache->active)
12572 {
12573 // If active pet is not alive it cant be summoned now
12574 // Player must explicitly summon and revive it
12575 if (petCache->alive)
12576 _spawnPet(petCache);
12577 else
12578 petCache->active = false;
12579
12580 return;
12581 }
12582 }
12583}
12584
12586{
12587 if (getPet() == nullptr)
12588 return;
12589
12591}
12592
12594{
12595 if (!IsInWorld() || !isAlive())
12596 return true;
12597
12598 if (isOnTaxi())
12599 return true;
12600
12601 // In classic pets were not despawned when mounted
12602 // In tbc and wotlk they despawned, but this was again changed around patch 4.1
12603#if VERSION_STRING == TBC || VERSION_STRING == WotLK
12604#ifdef FT_VEHICLES
12605 if (isMounted() || isOnVehicle())
12606#else
12607 if (isMounted())
12608#endif
12609 {
12610 if (const auto* const pet = getPet())
12611 {
12612 if (!pet->isAlive())
12613 return false;
12614
12615 if (!pet->isPermanentSummon())
12616 return false;
12617
12618 if (m_bg != nullptr && m_bg->isArena())
12619 return false;
12620
12621 // For some reason permanent water elemental is not despawned
12622 if (pet->getEntry() == PET_WATER_ELEMENTAL_NEW)
12623 return false;
12624 }
12625
12626 return true;
12627 }
12628#endif
12629
12630 return false;
12631}
12632
12634{
12635 const auto copiedCachedSlots = m_cachedPetSlots;
12636 for (const auto& [slot, petId] : std::as_const(copiedCachedSlots))
12637 {
12638 // Just check active slots
12639 if (slot >= PET_SLOT_MAX_ACTIVE_SLOT)
12640 break;
12641
12642 auto* const petCache = getModifiablePetCache(petId);
12643 if (petCache == nullptr)
12644 continue;
12645
12646 if (petCache->active)
12647 {
12648 // Summoned pets can be completely deleted since they can be resummoned anyway
12649 if (petCache->type == PET_TYPE_HUNTER)
12650 petCache->active = false;
12651 else
12652 removePetCache(petCache->number);
12653 }
12654 }
12655}
12656
12661
12664
12666{
12667 if (summonPet)
12668 {
12669 for (const auto& spellId : m_spellSet)
12670 {
12671 if (const auto spellInfo = sSpellMgr.getSpellInfo(spellId))
12672 {
12673 if (spellInfo->custom_c_is_flags & SPELL_FLAG_IS_CASTED_ON_PET_SUMMON_PET_OWNER)
12674 {
12675 this->removeAllAurasByIdForGuid(spellId, this->getGuid());
12676 SpellCastTargets targets(this->getGuid());
12677 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
12678 spell->prepare(&targets);
12679 }
12680
12681 if (spellInfo->custom_c_is_flags & SPELL_FLAG_IS_CASTED_ON_PET_SUMMON_ON_PET)
12682 {
12683 this->removeAllAurasByIdForGuid(spellId, this->getGuid());
12684 SpellCastTargets targets(summonPet->getGuid());
12685 Spell* spell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
12686 spell->prepare(&targets);
12687 }
12688 }
12689 }
12690
12691 for (const auto& aura : getAuraList())
12692 if (aura && aura->getSpellInfo()->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_ON_PET)
12693 aura->removeAura();
12694 }
12695}
12696
12698{
12699 for (const auto& aura : getAuraList())
12700 if (aura && aura->getSpellInfo()->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)
12701 aura->removeAura();
12702}
12703
12705void Player::setSummonedObject(Object* summonedObject) { m_summonedObject = summonedObject; }
12706
12707void Player::_spawnPet(PetCache const* petCache)
12708{
12709 const auto pet = sObjectMgr.createPet(petCache->entry, nullptr);
12710 if (!pet->loadFromDB(this, petCache))
12711 {
12712 pet->DeleteMe();
12713 return;
12714 }
12715
12716 // TODO: find a better way to handle these -Appled
12717 if (petCache->spellid)
12718 {
12719 removeAllAurasById(18789);
12720 removeAllAurasById(18790);
12721 removeAllAurasById(18791);
12722 removeAllAurasById(18792);
12723 removeAllAurasById(35701);
12724 }
12725}
12726
12727//////////////////////////////////////////////////////////////////////////////////////////
12728// Misc
12730{
12731 for (uint8_t i = 0; i < InstanceDifficulty::MAX_DIFFICULTY; ++i)
12732 m_boundInstances[i].clear();
12733
12734 auto group = getGroup();
12735
12736 // 0 1 2 3 4 5
12737 auto result = CharacterDatabase.Query("SELECT id, permanent, map, difficulty, extendState, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = %u", getGuidLow());
12738 if (result)
12739 {
12740 do
12741 {
12742 Field* fields = result->Fetch();
12743
12744 bool perm = fields[1].asBool();
12745 uint32_t mapId = fields[2].asUint16();
12746 uint32_t instanceId = fields[0].asUint32();
12747 uint8_t difficulty = fields[3].asUint8();
12748 BindExtensionState extendState = BindExtensionState(fields[4].asUint8());
12749
12750 time_t resetTime = time_t(fields[5].asUint64());
12751 bool deleteInstance = false;
12752
12753 WDB::Structures::MapEntry const* mapEntry = sMapStore.lookupEntry(mapId);
12754#if VERSION_STRING > WotLK
12755 std::string mapname = mapEntry ? mapEntry->map_name[0] : "Unknown";
12756#else
12757 std::string mapname = mapEntry ? mapEntry->map_name[sWorld.getDbcLocaleLanguageId()] : "Unknown";
12758#endif
12759
12760 if (!mapEntry || !mapEntry->isInstanceMap())
12761 {
12762 sLogger.failure("Player::loadBoundInstances: Player '{}' ({}) has bind to not existed or not dungeon map {} ({})",
12763 getName(), getGuid(), mapId, mapname);
12764 deleteInstance = true;
12765 }
12766 else if (difficulty >= InstanceDifficulty::MAX_DIFFICULTY)
12767 {
12768 sLogger.failure("entities.player", "Player::loadBoundInstances: player '{}' ({}) has bind to not existed difficulty {} instance for map {} ({})",
12769 getName(), getGuid(), difficulty, mapId, mapname);
12770 deleteInstance = true;
12771 }
12772 else
12773 {
12775 if (!mapDiff)
12776 {
12777 sLogger.failure("entities.player", "Player::loadBoundInstances: player '{}' ({}) has bind to not existed difficulty {} instance for map {} ({})",
12778 getName(), getGuid(), difficulty, mapId, mapname);
12779 deleteInstance = true;
12780 }
12781 else if (!perm && group)
12782 {
12783 sLogger.failure("entities.player", "Player::loadBoundInstances: player '{}' ({}) is in group {} but has a non-permanent character bind to map {} ({}), {}, {}",
12784 getName(), getGuid(), group->GetGUID(), mapId, mapname, instanceId, difficulty);
12785 deleteInstance = true;
12786 }
12787 }
12788
12789 if (deleteInstance)
12790 {
12791 CharacterDatabase.Execute("DELETE FROM character_instance WHERE guid = %u AND instance = %u", getGuidLow(), instanceId);
12792 continue;
12793 }
12794
12795 // since non permanent binds are always solo bind, they can always be reset
12796 if (InstanceSaved* save = sInstanceMgr.addInstanceSave(mapId, instanceId, InstanceDifficulty::Difficulties(difficulty), resetTime, !perm, true))
12797 bindToInstance(save, perm, extendState, true);
12798
12799 } while (result->NextRow());
12800 }
12801}
12802
12804{
12805#if VERSION_STRING > TBC
12806 // some instances only have one difficulty
12807 auto const* mapDiff = getDownscaledMapDifficultyData(mapId, difficulty);
12808 if (!mapDiff)
12809 return nullptr;
12810#endif
12811
12812 BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapId);
12813 if (itr != m_boundInstances[difficulty].end())
12814 if (itr->second.extendState || withExpired)
12815 return &itr->second;
12816 return nullptr;
12817}
12818
12820{
12821 InstancePlayerBind* pBind = getBoundInstance(mapId, getDifficulty(isRaid));
12822 InstanceSaved* pSave = pBind ? pBind->save : nullptr;
12823 if (!pBind || !pBind->perm)
12824 if (auto group = getGroup())
12825 if (InstanceGroupBind* groupBind = group->getBoundInstance(getDifficulty(isRaid), mapId))
12826 pSave = groupBind->save;
12827
12828 return pSave;
12829}
12830
12832{
12833 BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
12834 unbindInstance(itr, difficulty, unload);
12835}
12836
12837void Player::unbindInstance(BoundInstancesMap::iterator& itr, InstanceDifficulty::Difficulties difficulty, bool unload)
12838{
12839 if (itr != m_boundInstances[difficulty].end())
12840 {
12841 if (!unload)
12842 {
12843 CharacterDatabase.Execute("DELETE FROM character_instance WHERE guid = %u AND instance = %u", getGuidLow(), itr->second.save->getInstanceId());
12844 }
12845
12846#if VERSION_STRING > TBC
12847 if (itr->second.perm)
12848 getSession()->sendCalendarRaidLockout(itr->second.save, false);
12849#endif
12850 itr->second.save->removePlayer(this); // save can become invalid
12851 m_boundInstances[difficulty].erase(itr++);
12852 }
12853}
12854
12856{
12857 if (save)
12858 {
12859 InstancePlayerBind& bind = m_boundInstances[save->getDifficulty()][save->getMapId()];
12860 if (extendState == EXTEND_STATE_KEEP) // special flag, keep the player's current extend state when updating for new boss down
12861 {
12862 if (save == bind.save)
12863 extendState = bind.extendState;
12864 else
12865 extendState = EXTEND_STATE_NORMAL;
12866 }
12867 if (!load)
12868 {
12869 if (bind.save)
12870 {
12871 // update the save when the group kills a boss
12872 if (permanent != bind.perm || save != bind.save || extendState != bind.extendState)
12873 {
12874 CharacterDatabase.Execute("UPDATE character_instance SET instance = %u, permanent = %u, extendState = %u WHERE guid = %u AND instance = %u", save->getInstanceId(), permanent, extendState, getGuidLow(), bind.save->getInstanceId());
12875 }
12876 }
12877 else
12878 {
12879 CharacterDatabase.Execute("INSERT INTO character_instance (guid, instance, permanent, extendState) VALUES (%u, %u, %u, %u)", getGuidLow(), save->getInstanceId(), permanent, extendState);
12880 }
12881 }
12882
12883 if (bind.save != save)
12884 {
12885 if (bind.save)
12886 bind.save->removePlayer(this);
12887
12888 save->addPlayer(this);
12889 }
12890
12891 if (permanent)
12892 save->setCanReset(false);
12893
12894 bind.save = save;
12895 bind.perm = permanent;
12896 bind.extendState = extendState;
12897 return &bind;
12898 }
12899
12900 return nullptr;
12901}
12902
12904{
12905 InstanceSaved* mapSave = sInstanceMgr.getInstanceSave(m_pendingBindId);
12906 if (!mapSave)
12907 return;
12908
12910 data << uint32_t(0);
12911 sendPacket(&data);
12912 if (!isGMFlagSet())
12913 {
12914 bindToInstance(mapSave, true, EXTEND_STATE_KEEP);
12915#if VERSION_STRING > TBC
12916 getSession()->sendCalendarRaidLockout(mapSave, true);
12917#endif
12918 }
12919}
12920
12921void Player::setPendingBind(uint32_t instanceId, uint32_t bindTimer)
12922{
12923 m_pendingBindId = instanceId;
12924 m_pendingBindTimer = bindTimer;
12925}
12926
12928{
12929 uint32_t counter = 0;
12930
12932
12933 size_t p_counter = data.wpos();
12934 data << uint32_t(counter);
12935
12936 const auto now = Util::getTimeNow();
12937
12938 for (uint8_t i = 0; i < InstanceDifficulty::MAX_DIFFICULTY; ++i)
12939 {
12940 for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
12941 {
12942 InstancePlayerBind const& bind = itr->second;
12943 if (bind.perm)
12944 {
12945 InstanceSaved* save = bind.save;
12946 data << uint32_t(save->getMapId());
12947#if VERSION_STRING > TBC
12948 data << uint32_t(save->getDifficulty());
12949 data << uint64_t(save->getInstanceId());
12950 data << uint8_t(bind.extendState != EXTEND_STATE_EXPIRED);
12951 data << uint8_t(bind.extendState == EXTEND_STATE_EXTENDED);
12952
12953 time_t nextReset = save->getResetTime();
12955 nextReset = sInstanceMgr.getSubsequentResetTime(save->getMapId(), save->getDifficulty(), save->getResetTime());
12956
12957 data << uint32_t(nextReset - now);
12958#else
12959 time_t nextReset = save->getResetTime();
12961 nextReset = sInstanceMgr.getSubsequentResetTime(save->getMapId(), save->getDifficulty(), save->getResetTime());
12962
12963 data << uint32_t(nextReset - now);
12964
12965 data << uint32_t(save->getInstanceId());
12966 data << uint32_t(counter);
12967#endif
12968
12969 ++counter;
12970 }
12971 }
12972 }
12973 data.put<uint32_t>(p_counter, counter);
12974 sendPacket(&data);
12975}
12976
12978{
12979 bool hasBeenSaved = false;
12980 WorldPacket data;
12981
12982 for (uint8_t i = 0; i < InstanceDifficulty::MAX_DIFFICULTY; ++i)
12983 {
12984 for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
12985 {
12986 if (itr->second.perm)
12987 {
12988 hasBeenSaved = true;
12989 break;
12990 }
12991 }
12992 }
12993
12994 // true or false means, whether you have current raid/heroic instances
12996 data << uint32_t(hasBeenSaved);
12997 sendPacket(&data);
12998
12999 if (!hasBeenSaved)
13000 return;
13001
13002 for (uint8_t i = 0; i < InstanceDifficulty::MAX_DIFFICULTY; ++i)
13003 {
13004 for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
13005 {
13006 if (itr->second.perm)
13007 {
13009 data << uint32_t(itr->second.save->getMapId());
13010 sendPacket(&data);
13011 }
13012 }
13013 }
13014}
13015
13017{
13018 // type of warning, based on the time remaining until reset
13019 uint32_t type;
13020 if (welcome)
13021 type = RAID_INSTANCE_WELCOME;
13022 else if (time > 21600)
13023 type = RAID_INSTANCE_WELCOME;
13024 else if (time > 3600)
13026 else if (time > 300)
13028 else
13030
13031 WorldPacket data(SMSG_RAID_INSTANCE_MESSAGE, 4 + 4 + 4 + 4);
13032 data << uint32_t(type);
13033 data << uint32_t(mapid);
13034 data << uint32_t(difficulty); // difficulty
13035 data << uint32_t(time);
13036
13037 if (type == RAID_INSTANCE_WELCOME)
13038 {
13039 data << uint8_t(0); // is locked
13040 data << uint8_t(0); // is extended, ignored if prev field is 0
13041 }
13042
13043 sendPacket(&data);
13044}
13045
13046void Player::resetInstances(uint8_t method, bool isRaid)
13047{
13048 // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN
13049
13050 // we assume that when the difficulty changes, all instances that can be reset will be
13052
13053 for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();)
13054 {
13055 InstanceSaved* p = itr->second.save;
13056 WDB::Structures::MapEntry const* entry = sMapStore.lookupEntry(itr->first);
13057 if (!entry || entry->isRaid() != isRaid || !p->canReset())
13058 {
13059 ++itr;
13060 continue;
13061 }
13062
13063 if (method == INSTANCE_RESET_ALL)
13064 {
13065 // the "reset all instances" method can only reset normal maps
13067 {
13068 ++itr;
13069 continue;
13070 }
13071 }
13072
13073 // if the map is loaded, reset it
13074 WorldMap* map = sMapMgr.findWorldMap(p->getMapId(), p->getInstanceId());
13075 if (map && map->getBaseMap()->isInstanceMap())
13076 if (!reinterpret_cast<InstanceMap*>(map)->reset(method))
13077 {
13078 ++itr;
13079 continue;
13080 }
13081
13082 // since this is a solo instance there should not be any players inside
13083 if (method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
13085
13086 p->deleteFromDB();
13087 m_boundInstances[diff].erase(itr++);
13088
13089 // the following should remove the instance save from the manager and delete it as well
13090 p->removePlayer(this);
13091 }
13092}
13093
13095{
13096 // reasons for instance reset failure:
13097 // 0: There are players inside the instance.
13098 // 1: There are players offline in your party.
13099 // 2: There are players in your party attempting to zone into an instance.
13101 data << uint32_t(reason);
13102 data << uint32_t(MapId);
13103 sendPacket(&data);
13104}
13105
13107{
13108 auto result = CharacterDatabase.Query("SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = %u", getSession()->GetAccountId());
13109 if (!result)
13110 return;
13111
13112 do
13113 {
13114 Field* fields = result->Fetch();
13115 m_instanceResetTimes.insert(InstanceTimeMap::value_type(fields[0].asUint32(), fields[1].asUint64()));
13116 } while (result->NextRow());
13117}
13118
13120{
13121 //\todo: Max Instances Per Hour is per Default 5 add these to Configs
13122 if (m_instanceResetTimes.size() < 5)
13123 return true;
13124
13125 return m_instanceResetTimes.find(instanceId) != m_instanceResetTimes.end();
13126}
13127
13128void Player::addInstanceEnterTime(uint32_t instanceId, time_t enterTime)
13129{
13130 if (m_instanceResetTimes.find(instanceId) == m_instanceResetTimes.end())
13131 m_instanceResetTimes.insert(InstanceTimeMap::value_type(instanceId, enterTime + HOUR));
13132}
13133
13135{
13136 if (m_instanceResetTimes.empty())
13137 return;
13138
13139 CharacterDatabase.Execute("DELETE FROM account_instance_times WHERE accountId = %u", getSession()->GetAccountId());
13140
13141 for (InstanceTimeMap::const_iterator itr = m_instanceResetTimes.begin(); itr != m_instanceResetTimes.end(); ++itr)
13142 {
13143 CharacterDatabase.Execute("INSERT INTO account_instance_times (accountId, instanceId, releaseTime) VALUES (%u, %u, %u)", getSession()->GetAccountId(), itr->first, itr->second);
13144 }
13145}
13146
13147
13149{
13150 uint32_t maxRating = 0;
13151
13152 if (m_playerInfo)
13153 {
13154 for (uint8_t index = 0; index < NUM_ARENA_TEAM_TYPES; index++)
13155 {
13156 if (m_arenaTeams[index] != nullptr)
13157 {
13158 if (ArenaTeamMember* arenaTeamMember = m_arenaTeams[index]->getMemberByGuid(m_playerInfo->guid))
13159 {
13160 if (arenaTeamMember->PersonalRating > maxRating)
13161 maxRating = arenaTeamMember->PersonalRating;
13162 }
13163 else
13164 {
13165 sLogger.failure("{}: GetMemberByGuid returned NULL for player guid = {}", __FUNCTION__, m_playerInfo->guid);
13166 }
13167 }
13168 }
13169 }
13170 return maxRating;
13171}
13172
13173// Fills fields from firstField to firstField+fieldsNum-1 with integers from the string
13174void Player::loadFieldsFromString(const char* string, uint16_t /*firstField*/, uint32_t fieldsNum)
13175{
13176 if (string == nullptr)
13177 return;
13178
13179 char* start = (char*)string;
13180 for (uint16_t Counter = 0; Counter < fieldsNum; Counter++)
13181 {
13182 char* end = strchr(start, ',');
13183 if (!end)
13184 break;
13185
13186 *end = 0;
13187 setExploredZone(Counter, std::stoul(start));
13188 start = end + 1;
13189 }
13190}
13191
13193{
13194 int32_t modifier = 0;
13195
13196#if VERSION_STRING != Classic
13197 setExpertise(0);
13199
13200 for (const auto& aurEff : getAuraEffectList(SPELL_AURA_EXPERTISE))
13201 {
13202 SpellInfo const* spellInfo = aurEff->getAura()->getSpellInfo();
13203 int32_t val = aurEff->getEffectDamage();
13204
13205 if (spellInfo->getEquippedItemSubClass() != 0)
13206 {
13209
13210 uint32_t reqskillMH = 0;
13211 uint32_t reqskillOH = 0;
13212
13213 if (item_mainhand)
13214 reqskillMH = spellInfo->getEquippedItemSubClass() & (((uint32_t)1) << item_mainhand->getItemProperties()->SubClass);
13215
13216 if (item_offhand)
13217 reqskillOH = spellInfo->getEquippedItemSubClass() & (((uint32_t)1) << item_offhand->getItemProperties()->SubClass);
13218
13219 if (reqskillMH != 0 || reqskillOH != 0)
13220 modifier = +val;
13221 }
13222 else
13223 modifier += val;
13224 }
13225
13228#endif
13229 updateStats();
13230}
13231
13233{
13234#if VERSION_STRING == WotLK
13235 if (auto const* currency_type_entry = sCurrencyTypesStore.lookupEntry(itemId))
13236 {
13237 if (apply)
13238 {
13239 uint64_t oldval = getKnownCurrencies();
13240 uint64_t newval = oldval | (1LL << (currency_type_entry->bit_index - 1));
13241 setKnownCurrencies(newval);
13242 }
13243 else
13244 {
13245 uint64_t oldval = getKnownCurrencies();
13246 uint64_t newval = oldval & ~(1LL << (currency_type_entry->bit_index - 1));
13247 setKnownCurrencies(newval);
13248 }
13249 }
13250#else
13251 if (itemId == 0 || apply) { return; }
13252#endif
13253}
13254
13256{
13257 Loot loot1;
13258 sLootMgr.fillItemLoot(this, &loot1, itemId, 0);
13259
13260 for (const auto& item : loot1.items)
13261 {
13262 uint32_t looteditemid = item.itemproto->ItemId;
13263 uint32_t count = item.count;
13264
13265 getItemInterface()->AddItemById(looteditemid, count, 0);
13266 }
13267}
13268
13270{
13271 if (InstanceMap* instance = sMapMgr.findInstanceMap(GetInstanceID()))
13272 if (instance->getScript())
13273 instance->getScript()->displayDataStateList(this);
13274}
13275
13277{
13278 if (InstanceMap* instance = sMapMgr.findInstanceMap(GetInstanceID()))
13279 if (instance->getScript())
13280 instance->getScript()->displayTimerList(this);
13281}
13283{
13284 if (InstanceMap* instance = sMapMgr.findInstanceMap(GetInstanceID()))
13285 if (instance->getScript())
13286 instance->getScript()->getCreatureSetForEntry(_creatureEntry, true, this);
13287}
13288
13290{
13291 std::stringstream dmglog;
13292
13293 if ((spellId != 0) && (worldConfig.limit.maxSpellDamageCap > 0))
13294 {
13295 if (damage > worldConfig.limit.maxSpellDamageCap)
13296 {
13297 dmglog << "Dealt " << damage << " with spell " << spellId;
13298
13299 sCheatLog.writefromsession(m_session, dmglog.str().c_str());
13300
13301 if (worldConfig.limit.disconnectPlayerForExceedingLimits != 0)
13303
13304 damage = worldConfig.limit.maxSpellDamageCap;
13305 }
13306 }
13307 else if ((worldConfig.limit.maxAutoAttackDamageCap > 0) && (damage > worldConfig.limit.maxAutoAttackDamageCap))
13308 {
13309 dmglog << "Dealt " << damage << " with auto attack";
13310 sCheatLog.writefromsession(m_session, dmglog.str().c_str());
13311
13312 if (worldConfig.limit.disconnectPlayerForExceedingLimits != 0)
13314
13315 damage = worldConfig.limit.maxAutoAttackDamageCap;
13316 }
13317
13318 if (worldConfig.limit.broadcastMessageToGmOnExceeding != 0)
13319 sendReportToGmMessage(getName(), dmglog.str());
13320
13321 return damage;
13322}
13323
13325{
13327 if (item == nullptr || item->getItemProperties()->InventoryType != INVTYPE_SHIELD)
13328 return 0;
13329
13330 float block_multiplier = (100.0f + this->m_modBlockAbsorbValue) / 100.0f;
13331 if (block_multiplier < 1.0f)
13332 block_multiplier = 1.0f;
13333
13334 return Util::float2int32((item->getItemProperties()->Block + this->m_modBlockValueFromSpells + this->getCombatRating(CR_BLOCK) + this->getStat(STAT_STRENGTH) / 2.0f - 1.0f) * block_multiplier);
13335}
13336
13338{
13339 float feralAttackPower = 0.0f;
13340
13341 Item* applyItem = item;
13342 if (applyItem == nullptr)
13344
13345 if (applyItem)
13346 {
13347 float delay = static_cast<float>(applyItem->getItemProperties()->Delay) / 1000.0f;
13348 delay = std::max(1.0f, delay);
13349 float dps = ((applyItem->getItemProperties()->Damage[0].Min + applyItem->getItemProperties()->Damage[0].Max) / 2) / delay;
13350 if (dps > 54.8f)
13351 feralAttackPower = (dps - 54.8f) * 14;
13352 }
13353 modifyBonuses(ITEM_MOD_FERAL_ATTACK_POWER, static_cast<int32_t>(feralAttackPower), apply);
13354}
13355
13356bool Player::saveReputations(bool newCharacter, QueryBuffer* buf)
13357{
13358 if (!newCharacter && (buf == nullptr))
13359 return false;
13360
13361 std::stringstream ds;
13362 uint32_t guid = getGuidLow();
13363
13364 ds << "DELETE FROM playerreputations WHERE guid = '";
13365 ds << guid;
13366 ds << "';";
13367
13368 if (!newCharacter)
13369 buf->AddQueryStr(ds.str());
13370 else
13371 CharacterDatabase.ExecuteNA(ds.str().c_str());
13372
13373 for (ReputationMap::iterator itr = m_reputation.begin(); itr != m_reputation.end(); ++itr)
13374 {
13375 std::stringstream ss;
13376
13377 ss << "INSERT INTO playerreputations VALUES('";
13378 ss << getGuidLow() << "','";
13379 ss << itr->first << "','";
13380 ss << uint32_t(itr->second->flag) << "','";
13381 ss << itr->second->baseStanding << "','";
13382 ss << itr->second->standing << "');";
13383
13384 if (!newCharacter)
13385 buf->AddQueryStr(ss.str());
13386 else
13387 CharacterDatabase.ExecuteNA(ss.str().c_str());
13388 }
13389
13390 return true;
13391}
13392
13393bool Player::saveSpells(bool newCharacter, QueryBuffer* buf)
13394{
13395 if (!newCharacter && buf == nullptr)
13396 return false;
13397
13398 std::stringstream ds;
13399 uint32_t guid = getGuidLow();
13400
13401 ds << "DELETE FROM playerspells WHERE GUID = '";
13402 ds << guid;
13403 ds << "';";
13404
13405 if (!newCharacter)
13406 buf->AddQueryStr(ds.str());
13407 else
13408 CharacterDatabase.ExecuteNA(ds.str().c_str());
13409
13410 for (const auto& spellid : m_spellSet)
13411 {
13412 std::stringstream ss;
13413
13414 ss << "INSERT INTO playerspells VALUES('";
13415 ss << guid << "','";
13416 ss << spellid << "');";
13417
13418 if (!newCharacter)
13419 buf->AddQueryStr(ss.str());
13420 else
13421 CharacterDatabase.ExecuteNA(ss.str().c_str());
13422 }
13423
13424 return true;
13425}
13426
13428{
13429 if (result == nullptr)
13430 return false;
13431
13432 do
13433 {
13434 Field* fields = result->Fetch();
13435 uint32_t spellid = fields[0].asUint32();
13436
13437 const auto* const spellInfo = sSpellMgr.getSpellInfo(spellid);
13438 if (spellInfo == nullptr)
13439 continue;
13440
13441 if (sSpellMgr.isSpellDisabled(spellid))
13442 continue;
13443
13444 m_deletedSpellSet.emplace(spellid);
13445 } while (result->NextRow());
13446
13447 return true;
13448}
13449
13451{
13452 if (!newCharacter && buf == nullptr)
13453 return false;
13454
13455 std::stringstream ds;
13456 uint32_t guid = getGuidLow();
13457
13458 ds << "DELETE FROM playerdeletedspells WHERE GUID = '";
13459 ds << guid;
13460 ds << "';";
13461
13462 if (!newCharacter)
13463 buf->AddQueryStr(ds.str());
13464 else
13465 CharacterDatabase.ExecuteNA(ds.str().c_str());
13466
13467 for (const auto& spellid : m_deletedSpellSet)
13468 {
13469 std::stringstream ss;
13470
13471 ss << "INSERT INTO playerdeletedspells VALUES('";
13472 ss << guid << "','";
13473 ss << spellid << "');";
13474
13475 if (!newCharacter)
13476 buf->AddQueryStr(ss.str());
13477 else
13478 CharacterDatabase.ExecuteNA(ss.str().c_str());
13479 }
13480
13481 return true;
13482}
13483
13484bool Player::saveSkills(bool newCharacter, QueryBuffer* buf)
13485{
13486 if (!newCharacter && buf == nullptr)
13487 return false;
13488
13489 std::stringstream ds;
13490 uint32_t guid = getGuidLow();
13491
13492 ds << "DELETE FROM playerskills WHERE GUID = '";
13493 ds << guid;
13494 ds << "';";
13495
13496 if (!newCharacter)
13497 buf->AddQueryStr(ds.str());
13498 else
13499 CharacterDatabase.ExecuteNA(ds.str().c_str());
13500
13501 for (SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end(); ++itr)
13502 {
13503 uint32_t skillid = itr->first;
13504 uint32_t currval = itr->second.CurrentValue;
13505 uint32_t maxval = itr->second.MaximumValue;
13506
13507 // Skip only initialized values
13508 if (currval == 0)
13509 continue;
13510
13511 std::stringstream ss;
13512
13513 ss << "INSERT INTO playerskills VALUES('";
13514 ss << guid << "','";
13515 ss << skillid << "','";
13516 ss << currval << "','";
13517 ss << maxval << "');";
13518
13519 if (!newCharacter)
13520 buf->AddQueryStr(ss.str());
13521 else
13522 CharacterDatabase.ExecuteNA(ss.str().c_str());
13523 }
13524
13525 return true;
13526}
13527
13529{
13530 if (!IsInWorld())
13531 return;
13532
13534 return;
13535
13536 if (getWorldMap()->getCellByCoords(GetPositionX(), GetPositionY()) == nullptr)
13537 return;
13538
13539 uint32_t AreaId = 0;
13540 uint32_t ZoneId = 0;
13541
13542 getWorldMap()->getZoneAndAreaId(GetPhase(), ZoneId, AreaId, GetPosition());
13543
13544 ////////////////////////////////////////////////////////////////////////////////////////////////////
13545 // Cheks for Casting a Spell in Specified Area / Zone :D
13546
13547 // Spells get Casted in specified Area
13548 SpellAreaForAreaMapBounds saBounds = sSpellMgr.getSpellAreaForAreaMapBounds(AreaId);
13549 for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
13550 if (itr->second->autoCast && itr->second->fitsToRequirements(this, ZoneId, AreaId))
13551 if (!hasAurasWithId(itr->second->spellId))
13552 castSpell(this, itr->second->spellId, true);
13553
13554
13555 // Some spells applied at enter into zone (with subzones)
13556 SpellAreaForAreaMapBounds szBounds = sSpellMgr.getSpellAreaForAreaMapBounds(ZoneId);
13557 for (SpellAreaForAreaMap::const_iterator itr = szBounds.first; itr != szBounds.second; ++itr)
13558 if (itr->second->autoCast && itr->second->fitsToRequirements(this, ZoneId, AreaId))
13559 if (!hasAurasWithId(itr->second->spellId))
13560 castSpell(this, itr->second->spellId, true);
13561
13562
13563 // Remove of Spells
13565 {
13566 if (auto* const aur = getAuraWithAuraSlot(i))
13567 {
13568 if (sSpellMgr.checkLocation(aur->getSpellInfo(), ZoneId, AreaId, this) == false)
13569 {
13570 SpellAreaMapBounds sab = sSpellMgr.getSpellAreaMapBounds(aur->getSpellId());
13571 if (sab.first != sab.second)
13572 removeAllAurasById(aur->getSpellId());
13573 }
13574 }
13575 }
13576}
13577
13582
13584{
13585 if (!m_hearthOfWildPct)
13586 return;
13587
13588 int tval;
13589 if (apply)
13590 tval = m_hearthOfWildPct;
13591 else
13592 tval = -m_hearthOfWildPct;
13593
13594 uint32_t shapeShiftForm = getShapeShiftForm();
13595
13596 if (shapeShiftForm == FORM_BEAR || shapeShiftForm == FORM_DIREBEAR)
13597 {
13600 updateStats();
13601
13602#if VERSION_STRING >= TBC
13603 updateChances();
13604#endif
13605 }
13606 else if (shapeShiftForm == FORM_CAT)
13607 {
13610 updateStats();
13611 }
13612}
13613
13614
13615void Player::_eventAttack(bool offhand)
13616{
13617 if (isCastingSpell())
13618 {
13619 setAttackTimer(offhand == true ? OFFHAND : MELEE, 100);
13620 return;
13621 }
13622
13623 if (isFeared() || isStunned())
13624 return;
13625
13626 Unit* pVictim = nullptr;
13627 if (getTargetGuid())
13628 pVictim = getWorldMap()->getUnit(getTargetGuid());
13629
13630 if (!pVictim)
13631 {
13632 sLogger.info("Player::Update: No valid current selection to attack, stopping attack");
13633 interruptHealthRegeneration(5000); //prevent clicking off creature for a quick heal
13635 return;
13636 }
13637
13638 if (!this->isValidTarget(pVictim))
13639 {
13642 return;
13643 }
13644
13645 if (!canReachWithAttack(pVictim))
13646 {
13647 if (m_AttackMsgTimer != 1)
13648 {
13649#if VERSION_STRING < Mop
13650 sendPacket(SmsgAttackSwingNotInRange().serialise().get());
13651#endif
13652 m_AttackMsgTimer = 1;
13653 }
13654 setAttackTimer(offhand == true ? OFFHAND : MELEE, 300);
13655 }
13656 else if (!isInFront(pVictim))
13657 {
13658 // We still have to do this one.
13659 if (m_AttackMsgTimer != 2)
13660 {
13661#if VERSION_STRING < Mop
13662 sendPacket(SmsgAttackSwingBadFacing().serialise().get());
13663#endif
13664 m_AttackMsgTimer = 2;
13665 }
13666 setAttackTimer(offhand == true ? OFFHAND : MELEE, 300);
13667 }
13668 else
13669 {
13670 m_AttackMsgTimer = 0;
13671
13672 // Set to weapon time.
13673 if (offhand)
13675 else
13677
13678 //pvp timeout reset
13679 if (pVictim->isPlayer())
13680 {
13681 if (static_cast<Player*>(pVictim)->m_cannibalize)
13682 {
13683 sEventMgr.RemoveEvents(pVictim, EVENT_CANNIBALIZE);
13685 static_cast<Player*>(pVictim)->m_cannibalize = false;
13686 }
13687 }
13688
13689 if (this->isStealthed())
13691
13692 if (getOnMeleeSpell() == 0 || offhand)
13693 strike(pVictim, (offhand ? OFFHAND : MELEE), nullptr, 0, 0, 0, false, false);
13694 else
13696 }
13697}
13698
13700{
13701 if (!getCharmGuid())
13702 return;
13703
13704 if (!IsInWorld())
13705 {
13706 setCharmGuid(0);
13707 sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHARM_ATTACK);
13708 return;
13709 }
13710
13711 if (getTargetGuid() == 0)
13712 {
13713 sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHARM_ATTACK);
13714 return;
13715 }
13716
13717 Unit* pVictim = getWorldMap()->getUnit(getTargetGuid());
13718 if (!pVictim)
13719 {
13720 sLogger.failure("WORLD: {} doesn't exist.", std::to_string(getTargetGuid()));
13721 sLogger.info("Player::Update: No valid current selection to attack, stopping attack");
13722 this->interruptHealthRegeneration(5000); //prevent clicking off creature for a quick heal
13723 // todo
13724 //removeUnitStateFlag(UNIT_STATE_ATTACKING);
13726 }
13727 else
13728 {
13729 Unit* currentCharm = getWorldMap()->getUnit(getCharmGuid());
13730 if (!currentCharm)
13731 return;
13732
13733 if (!currentCharm->canReachWithAttack(pVictim))
13734 {
13735 if (m_AttackMsgTimer == 0)
13736 m_AttackMsgTimer = 2000;
13737
13738 sEventMgr.ModifyEventTimeLeft(this, EVENT_PLAYER_CHARM_ATTACK, 100);
13739 }
13740 else if (!currentCharm->isInFront(pVictim))
13741 {
13742 if (m_AttackMsgTimer == 0)
13743 {
13744#if VERSION_STRING < Mop
13745 sendPacket(SmsgAttackSwingBadFacing().serialise().get());
13746#endif
13747 m_AttackMsgTimer = 2000; // 2 sec till next msg.
13748 }
13749
13750 sEventMgr.ModifyEventTimeLeft(this, EVENT_PLAYER_CHARM_ATTACK, 100);
13751 }
13752 else
13753 {
13754 if (!currentCharm->getOnMeleeSpell())
13755 {
13756 currentCharm->strike(pVictim, MELEE, nullptr, 0, 0, 0, false, false);
13757 }
13758 else
13759 {
13760 const auto spellInfo = sSpellMgr.getSpellInfo(currentCharm->getOnMeleeSpell());
13761 currentCharm->setOnMeleeSpell(0);
13762 Spell* spell = sSpellMgr.newSpell(currentCharm, spellInfo, true, nullptr);
13764 spell->prepare(&targets);
13765 }
13766 }
13767 }
13768}
13769
13771{
13772 m_attacking = true;
13773 dismount();
13774}
13775
13777{
13778 if (getCharmGuid() != 0)
13779 sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHARM_ATTACK);
13780
13781 m_attacking = false;
13782}
13783
13785{
13786 if (!IS_INSTANCE(GetMapId()) && !sEventMgr.HasEvent(this, EVENT_PLAYER_FORCED_RESURRECT)) //Should never be true
13787 sEventMgr.AddEvent(this, &Player::repopRequest, EVENT_PLAYER_FORCED_RESURRECT, forcedResurrectInterval, 1, 0); //in case he forgets to release spirit (afk or something)
13788
13790
13792}
13793
13794void Player::_savePet(QueryBuffer* buf, bool updateCurrentPetCache/* = false*/, Pet* currentPet/* = nullptr*/)
13795{
13796 // Remove any existing m_playerCreateInfo
13797 if (buf == nullptr)
13798 CharacterDatabase.Execute("DELETE FROM playerpets WHERE ownerguid = %u", getGuidLow());
13799 else
13800 buf->AddQuery("DELETE FROM playerpets WHERE ownerguid = %u", getGuidLow());
13801
13802 const auto* summon = currentPet != nullptr ? currentPet : getPet();
13803 if (summon && summon->IsInWorld()) // update PlayerPets array with current pet's m_playerCreateInfo
13804 {
13805 if (updateCurrentPetCache)
13806 {
13807 const auto playerPetCache = getPetCache(summon->getPetId());
13808 if (playerPetCache != nullptr && playerPetCache->active)
13809 summon->updatePetInfo(false);
13810 else
13811 summon->updatePetInfo(true);
13812 }
13813
13814 if (summon->isHunterPet()) // is a pet
13815 {
13816 // save pet spellz
13817 auto pn = summon->getPetId();
13818 if (buf == nullptr)
13819 CharacterDatabase.Execute("DELETE FROM playerpetspells WHERE ownerguid=%u AND petnumber=%u", getGuidLow(), pn);
13820 else
13821 buf->AddQuery("DELETE FROM playerpetspells WHERE ownerguid=%u AND petnumber=%u", getGuidLow(), pn);
13822
13823 for (const auto& [spell, state] : summon->getSpellMap())
13824 {
13825 if (buf == nullptr)
13826 CharacterDatabase.Execute("INSERT INTO playerpetspells VALUES(%u, %u, %u, %u)", getGuidLow(), pn, spell, state);
13827 else
13828 buf->AddQuery("INSERT INTO playerpetspells VALUES(%u, %u, %u, %u)", getGuidLow(), pn, spell, state);
13829 }
13830 }
13831 }
13832
13833 std::stringstream ss;
13834
13835 ss.rdbuf()->str("");
13836
13837 std::optional<uint8_t> currentPetId = std::nullopt;
13838 if (getPet() != nullptr && getPet()->isPermanentSummon())
13839 currentPetId = getPet()->getPetId();
13840
13841 std::vector<uint8_t> savedPetIds;
13842 savedPetIds.reserve(m_cachedPets.size());
13843
13844 auto foundActivePet = false;
13845 for (auto itr = m_cachedPets.cbegin(); itr != m_cachedPets.cend();)
13846 {
13847 auto* petCache = itr->second.get();
13848
13849 // Do some clean up to pet cache before save
13850 if (currentPetId.has_value())
13851 {
13852 // Set all other pets expect current pet to offline
13853 if (petCache->active && petCache->number != currentPetId.value())
13854 petCache->active = false;
13855
13856 // Remove all other cached pets from non-hunters expect current pet
13857 if (!isClassHunter() && getPetCount() > 1)
13858 {
13859 if (petCache->number != currentPetId.value())
13860 {
13861 std::erase_if(m_cachedPetSlots, [&petCache](const auto& slotItr) { return slotItr.second == petCache->number; });
13862 itr = m_cachedPets.erase(itr);
13863 continue;
13864 }
13865 }
13866 }
13867 else
13868 {
13869 // There can be only one active pet
13870 if (petCache->active)
13871 {
13872 if (petCache->slot >= PET_SLOT_FIRST_STABLE_SLOT)
13873 petCache->active = false;
13874 else if (foundActivePet)
13875 petCache->active = false;
13876 else
13877 foundActivePet = true;
13878 }
13879
13880 // Only hunters can have multiple pets saved
13881 if (!isClassHunter() && getPetCount() > 1)
13882 {
13883 if (!petCache->active)
13884 {
13885 std::erase_if(m_cachedPetSlots, [&petCache](const auto& slotItr) { return slotItr.second == petCache->number; });
13886 itr = m_cachedPets.erase(itr);
13887 continue;
13888 }
13889 }
13890 }
13891
13892 ss.rdbuf()->str("");
13893
13894 ss << "REPLACE INTO playerpets VALUES('"
13895 << getGuidLow() << "','"
13896 << std::to_string(petCache->number) << "','"
13897 << std::to_string(petCache->type) << "','"
13898 << petCache->name << "','"
13899 << petCache->entry << "','"
13900 << petCache->model << "','"
13901 << petCache->level << "','"
13902 << petCache->xp << "','"
13903 << std::to_string(petCache->slot) << "','"
13904 << petCache->active << "','"
13905 << petCache->alive << "','"
13906 << petCache->actionbar << "','"
13907 << static_cast<long>(petCache->reset_time) << "','"
13908 << petCache->reset_cost << "','"
13909 << petCache->spellid << "','"
13910 << std::to_string(petCache->petstate) << "','"
13911 << petCache->talentpoints << "','"
13912 << petCache->current_power << "','"
13913 << petCache->current_hp << "','"
13914 << petCache->current_happiness << "','"
13915 << petCache->renamable << "')";
13916
13917 if (buf == nullptr)
13918 CharacterDatabase.ExecuteNA(ss.str().c_str());
13919 else
13920 buf->AddQueryStr(ss.str());
13921
13922 savedPetIds.push_back(petCache->number);
13923 ++itr;
13924 }
13925
13926 // Cleanup as well pet spell table by removing spells from non existant pets
13927 ss.rdbuf()->str("");
13928 ss << "DELETE FROM playerpetspells WHERE ownerguid=" << getGuidLow();
13929 if (!savedPetIds.empty())
13930 {
13931 ss << " AND petnumber NOT IN (";
13932 for (auto itr = savedPetIds.cbegin(); itr != savedPetIds.cend();)
13933 {
13934 ss << std::to_string(*itr);
13935 if (++itr != savedPetIds.cend())
13936 ss << ", ";
13937 else
13938 ss << ")";
13939 }
13940 }
13941
13942 if (buf == nullptr)
13943 CharacterDatabase.ExecuteNA(ss.str().c_str());
13944 else
13945 buf->AddQueryStr(ss.str());
13946}
13947
13949{
13950 // Remove any existing
13951 if (buf == nullptr)
13952 CharacterDatabase.Execute("DELETE FROM playersummonspells WHERE ownerguid=%u", getGuidLow());
13953 else
13954 buf->AddQuery("DELETE FROM playersummonspells WHERE ownerguid=%u", getGuidLow());
13955
13956 // Save summon spells
13957 for (std::map<uint32_t, std::set<uint32_t> >::iterator itr = m_summonSpells.begin(); itr != m_summonSpells.end(); ++itr)
13958 {
13959 for (std::set<uint32_t>::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
13960 {
13961 if (buf == nullptr)
13962 CharacterDatabase.Execute("INSERT INTO playersummonspells VALUES(%u, %u, %u)", getGuidLow(), itr->first, (*it));
13963 else
13964 buf->AddQuery("INSERT INTO playersummonspells VALUES(%u, %u, %u)", getGuidLow(), itr->first, (*it));
13965 }
13966 }
13967}
13968
13970{
13971 SpellInfo const* sp = sSpellMgr.getSpellInfo(spellId);
13972 std::map<uint32_t, std::set<uint32_t> >::iterator itr = m_summonSpells.find(entry);
13973 if (itr == m_summonSpells.end())
13974 {
13975 m_summonSpells[entry].insert(spellId);
13976 }
13977 else
13978 {
13979 if (sp->hasSpellRanks())
13980 {
13981 std::set<uint32_t>::iterator it3;
13982 for (std::set<uint32_t>::iterator it2 = itr->second.begin(); it2 != itr->second.end();)
13983 {
13984 it3 = it2++;
13985 const auto se = sSpellMgr.getSpellInfo(*it3);
13986 if (se == nullptr || !se->hasSpellRanks())
13987 continue;
13988
13990 itr->second.erase(it3);
13991 }
13992 }
13993 itr->second.insert(spellId);
13994 }
13995}
13996
13998{
13999 std::map<uint32_t, std::set<uint32_t> >::iterator itr = m_summonSpells.find(entry);
14000 if (itr != m_summonSpells.end())
14001 {
14002 itr->second.erase(spellId);
14003 if (itr->second.size() == 0)
14004 m_summonSpells.erase(itr);
14005 }
14006}
14007
14008std::set<uint32_t>* Player::getSummonSpells(uint32_t entry)
14009{
14010 std::map<uint32_t, std::set<uint32_t> >::iterator itr = m_summonSpells.find(entry);
14011 if (itr != m_summonSpells.end())
14012 return &itr->second;
14013
14014 return nullptr;
14015}
14016
14018{
14019 m_maxPetNumber = 0;
14020 if (!result)
14021 return;
14022
14023 do
14024 {
14025 Field* fields = result->Fetch();
14026
14027 auto pet = std::make_unique<PetCache>();
14028 pet->number = fields[1].asUint8();
14029 pet->type = fields[2].asUint8();
14030 pet->name = fields[3].asCString();
14031 pet->entry = fields[4].asUint32();
14032
14033 // Check that creature properties exist
14034 const auto creatureProperties = sMySQLStore.getCreatureProperties(pet->entry);
14035 if (creatureProperties == nullptr)
14036 continue;
14037
14038 pet->model = fields[5].asUint32();
14039 pet->level = fields[6].asUint32();
14040 pet->xp = fields[7].asUint32();
14041 pet->slot = fields[8].asUint8();
14042 pet->active = fields[9].asBool();
14043 pet->alive = fields[10].asBool();
14044 pet->actionbar = fields[11].asCString();
14045 pet->reset_time = fields[12].asUint32();
14046 pet->reset_cost = fields[13].asUint32();
14047 pet->spellid = fields[14].asUint32();
14048 pet->petstate = fields[15].asUint8();
14049 pet->talentpoints = fields[16].asUint32();
14050 pet->current_power = fields[17].asUint32();
14051 pet->current_hp = fields[18].asUint32();
14052 pet->current_happiness = fields[19].asUint32();
14053 pet->renamable = fields[20].asBool();
14054
14055 // Check if there are pets using same slot
14056 // Also check for invalid pet slot in classic - wotlk
14057 // Could happen when server changes from cata to wotlk
14058 if (m_cachedPetSlots.contains(pet->slot)
14059#if VERSION_STRING < Cata
14060 || (pet->slot >= PET_SLOT_MAX_ACTIVE_SLOT && pet->slot < PET_SLOT_FIRST_STABLE_SLOT)
14061#endif
14062 )
14063 {
14064 if (pet->type != PET_TYPE_HUNTER)
14065 {
14066 // If other than hunter pet has invalid slot or is in duplicate slot, just remove it
14067 // They can be resummoned anyway
14068 continue;
14069 }
14070
14071#if VERSION_STRING >= Cata
14072 auto foundNewSlot = false;
14073 if (pet->slot < PET_SLOT_FIRST_STABLE_SLOT)
14074 {
14075 // Pet is in active slot, try find another active slot
14076 const auto freeActiveSlot = findFreeActivePetSlot();
14077 if (freeActiveSlot.has_value())
14078 {
14079 pet->slot = freeActiveSlot.value();
14080 foundNewSlot = true;
14081 }
14082 }
14083
14084 if (!foundNewSlot)
14085#endif
14086 {
14087 // Next try find free stable slot
14088 const auto freeStableSlot = findFreeStablePetSlot();
14089 if (!freeStableSlot.has_value())
14090 {
14091 // There were no free slots left, remove pet
14092 continue;
14093 }
14094
14095 pet->slot = freeStableSlot.value();
14096 }
14097 }
14098
14099 if (pet->type != PET_TYPE_HUNTER)
14100 {
14101 // Skip dead or inactive summoned pets
14102 // They should not be saved anyway
14103 if (!pet->active || !pet->alive)
14104 continue;
14105 }
14106
14107 // Pet in stables cannot be active
14108 if (pet->slot >= PET_SLOT_FIRST_STABLE_SLOT && pet->active)
14109 pet->active = false;
14110
14111 if (pet->number > m_maxPetNumber)
14112 m_maxPetNumber = pet->number;
14113
14114 addPetCache(std::move(pet), pet->number);
14115 } while (result->NextRow());
14116}
14117
14119{
14120 if (result)
14121 {
14122 do
14123 {
14124 Field* fields = result->Fetch();
14125 uint32_t entry = fields[1].asUint32();
14126 uint32_t spell = fields[2].asUint32();
14127 addSummonSpell(entry, spell);
14128 } while (result->NextRow());
14129 }
14130}
14131
14132void Player::saveToDB(bool newCharacter /* =false */)
14133{
14134 bool in_arena = false;
14135 std::unique_ptr<QueryBuffer> bufPtr = nullptr;
14136 QueryBuffer* buf = nullptr;
14137 if (!newCharacter)
14138 {
14139 bufPtr = std::make_unique<QueryBuffer>();
14140 buf = bufPtr.get();
14141 }
14142
14143 if (m_bg != nullptr && m_bg->isArena())
14144 in_arena = true;
14145
14146 //Calc played times
14147 uint32_t playedt = (uint32_t)UNIXTIME - m_playedTime[2];
14148 m_playedTime[0] += playedt;
14149 m_playedTime[1] += playedt;
14150 m_playedTime[2] += playedt;
14151
14152 // active cheats
14153 uint32_t active_cheats = PLAYER_CHEAT_NONE;
14155 active_cheats |= PLAYER_CHEAT_COOLDOWN;
14157 active_cheats |= PLAYER_CHEAT_CAST_TIME;
14159 active_cheats |= PLAYER_CHEAT_GOD_MODE;
14161 active_cheats |= PLAYER_CHEAT_POWER;
14163 active_cheats |= PLAYER_CHEAT_FLY;
14165 active_cheats |= PLAYER_CHEAT_AURA_STACK;
14167 active_cheats |= PLAYER_CHEAT_ITEM_STACK;
14169 active_cheats |= PLAYER_CHEAT_TRIGGERPASS;
14171 active_cheats |= PLAYER_CHEAT_TAXI;
14172
14173 std::stringstream ss;
14174
14175 ss << "REPLACE INTO characters VALUES (" << getGuidLow() << ", " << getSession()->GetAccountId() << ", " << "'" << m_name << "', "
14176 << uint32_t(getRace()) << ", " << uint32_t(getClass()) << ", " << uint32_t(getGender()) << ", " << getFactionTemplate() << ", ";
14177
14178 ss << uint32_t(getLevel()) << ", " << getXp() << ", " << active_cheats << ", ";
14179
14180 // exploration data
14181 ss << "'";
14182 for (uint8_t i = 0; i < WOWPLAYER_EXPLORED_ZONES_COUNT; ++i)
14183 ss << getExploredZone(i) << ",";
14184 ss << "', ";
14185
14186 saveSkills(newCharacter, buf);
14187
14188 ss << getWatchedFaction() << ", "
14189#if VERSION_STRING > Classic
14190 << getChosenTitle() << ", "
14191#else
14192 << uint32_t(0) << ", "
14193#endif
14194
14195#if VERSION_STRING > Classic
14196 << getKnownTitles(0) << ", "
14197#else
14198 << uint32_t(0) << ", "
14199#endif
14200
14201#if VERSION_STRING < WotLK
14202 << uint32_t(0) << ", " << uint32_t(0) << ", "
14203#else
14204 << getKnownTitles(1) << ", " << getKnownTitles(2) << ", "
14205#endif
14206 << getCoinage() << ", ";
14207
14208 if (getClass() == MAGE || getClass() == PRIEST || (getClass() == WARLOCK))
14209 ss << uint32_t(0) << ", "; // make sure ammo slot is 0 for these classes, otherwise it can mess up wand shoot
14210 else
14211#if VERSION_STRING < Cata
14212 ss << getAmmoId() << ", ";
14213#else
14214 ss << uint32_t(0) << ", ";
14215#endif
14216
14217 ss << getFreePrimaryProfessionPoints() << ", ";
14218
14219 ss << m_loadHealth << ", " << m_loadMana << ", " << uint32_t(getPvpRank()) << ", " << getPlayerBytes() << ", " << getPlayerBytes2() << ", ";
14220
14221 // Remove un-needed and problematic player flags from being saved :p
14224
14227
14230
14233
14236
14237#if VERSION_STRING < WotLK
14238 if (hasPlayerFlags(PLAYER_FLAG_FREE_FOR_ALL_PVP))
14239 removePlayerFlags(PLAYER_FLAG_FREE_FOR_ALL_PVP);
14240#endif
14241
14242#if VERSION_STRING >= WotLK
14243 if (hasPlayerFlags(PLAYER_FLAG_DEVELOPER))
14244 removePlayerFlags(PLAYER_FLAG_DEVELOPER);
14245#endif
14246
14247#if VERSION_STRING == TBC
14248 if (hasPlayerFlags(PLAYER_FLAG_SANCTUARY))
14249 removePlayerFlags(PLAYER_FLAG_SANCTUARY);
14250#endif
14251
14252 ss << getPlayerFlags() << ", " << std::to_string(getEnabledActionBars()) << ", ";
14253
14254 // if its an arena, save the entry coords instead of the normal position
14255 if (in_arena)
14256 ss << getBGEntryPosition().x << ", " << getBGEntryPosition().y << ", " << getBGEntryPosition().z << ", " << getBGEntryPosition().o << ", " << getBGEntryMapId() << ", ";
14257 else
14258 ss << m_position.x << ", " << m_position.y << ", " << m_position.z << ", " << m_position.o << ", " << m_mapId << ", ";
14259
14260 ss << m_zoneId << ", ";
14261
14262 // taxi mask
14263 ss << "'";
14264
14265 ss << m_taxi->saveTaximaskNodeToString();
14266
14267 ss << "', ";
14268
14269 ss << m_banned << ", '" << CharacterDatabase.EscapeString(m_banreason) << "', " << uint32_t(UNIXTIME) << ", ";
14270
14271 //online state
14272 if (getSession()->_loggingOut || newCharacter)
14273 ss << "0, ";
14274 else
14275 ss << "1, ";
14276
14277 ss << getBindPosition().x << ", " << getBindPosition().y << ", " << getBindPosition().z << ", " << getBindPosition().o << ", " << getBindMapId() << ", " << getBindZoneId() << ", ";
14278
14279 ss << uint32_t(m_isResting) << ", " << uint32_t(m_restState) << ", " << uint32_t(m_restAmount) << ", ";
14280
14281 ss << "'" << uint32_t(m_playedTime[0]) << " " << uint32_t(m_playedTime[1]) << " " << uint32_t(playedt) << "', ";
14282
14283 ss << uint32_t(m_deathState) << ", " << m_talentResetsCount << ", " << m_firstLogin << ", " << m_loginFlag << ", " << m_arenaPoints << ", " << (uint32_t)m_stableSlotCount << ", ";
14284
14285 // instances
14286 if (in_arena)
14287 ss << getBGEntryInstanceId() << ", ";
14288 else
14289 ss << m_instanceId << ", ";
14290
14291 ss << getBGEntryMapId() << ", " << getBGEntryPosition().x << ", " << getBGEntryPosition().y << ", " << getBGEntryPosition().z << ", " << getBGEntryPosition().o << ", " << getBGEntryInstanceId() << ", ";
14292
14293 // taxi destination
14294 ss << "'";
14295 ss << m_taxi->saveTaxiDestinationsToString();
14296 ss << "', ";
14297
14298 // last node
14299 if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(getMovementManager()->getCurrentMovementGenerator()))
14300 ss << flight->getCurrentNode() << ", ";
14301 else
14302 ss << uint32_t(0) << ", ";
14303
14304 const auto transport = this->GetTransport();
14305 if (!transport)
14306 ss << uint32_t(0) << ",'0','0','0','0'" << ", ";
14307 else
14308 ss << transport->getEntry() << ",'" << GetTransOffsetX() << "','" << GetTransOffsetY() << "','" << GetTransOffsetZ() << "','" << GetTransOffsetO() << "'" << ", ";
14309
14310 saveSpells(newCharacter, buf);
14311
14312 saveDeletedSpells(newCharacter, buf);
14313
14314 saveReputations(newCharacter, buf);
14315
14316 // Add player action bars
14317#ifdef FT_DUAL_SPEC
14318 for (uint8_t s = 0; s < MAX_SPEC_COUNT; ++s)
14319 {
14320 ss << "'";
14321 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
14322 {
14323 ss << uint32_t(m_specs[s].getActionButton(i).Action) << ","
14324 << uint32_t(m_specs[s].getActionButton(i).Type) << ","
14325 << uint32_t(m_specs[s].getActionButton(i).Misc) << ",";
14326 }
14327 ss << "'" << ", ";
14328 }
14329#else
14330 ss << "'";
14331 for (uint8_t i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
14332 {
14333 ss << uint32_t(m_spec.getActionButton(i).Action) << ","
14334 << uint32_t(m_spec.getActionButton(i).Type) << ","
14335 << uint32_t(m_spec.getActionButton(i).Misc) << ",";
14336 }
14337 ss << "'" << ", " << "''" << ", ";
14338#endif
14339
14340 if (!newCharacter)
14341 {
14342 saveAuras(ss);
14343 ss << ", ";
14344 }
14345 else
14346 {
14347 ss << "''" << ", ";
14348 }
14349
14350 // Add player finished quests
14351 ss << "'";
14352 for (auto finishedQuests = m_finishedQuests.begin(); finishedQuests != m_finishedQuests.end(); ++finishedQuests)
14353 ss << (*finishedQuests) << ",";
14354 ss << "'" << ", ";
14355
14356 // add finished dailies
14357 ss << "'";
14358 for (auto finishedDailies : getFinishedDailies())
14359 ss << finishedDailies << ",";
14360 ss << "'" << ", ";
14361
14362 ss << m_honorRolloverTime << ", " << m_killsToday << ", " << m_killsYesterday << ", " << m_killsLifetime << ", " << m_honorToday << ", " << m_honorYesterday << ", " << m_honorPoints << ", ";
14363
14364 ss << uint32_t(getDrunkValue()) << ", ";
14365
14366 // TODO Remove
14367#ifdef FT_DUAL_SPEC
14368 for (uint8_t s = 0; s < MAX_SPEC_COUNT; ++s)
14369 {
14370 ss << "'";
14371 for (uint8_t i = 0; i < GLYPHS_COUNT; ++i)
14372 ss << uint32_t(m_specs[s].getGlyph(i)) << ",";
14373
14374 ss << "', '";
14375 for (const auto& [talentId, rank] : m_specs[s].getTalents())
14376 ss << uint32_t(talentId) << "," << uint32_t(rank) << ",";
14377
14378 ss << "'" << ", ";
14379 }
14380#else
14381 ss << "'', '";
14382 for (const auto& [talentId, rank] : m_spec.getTalents())
14383 ss << talentId << "," << rank << ",";
14384
14385 ss << "', '', '', ";
14386#endif
14387
14388 ss << uint32_t(m_talentSpecsCount) << ", " << uint32_t(m_talentActiveSpec) << ", ";
14389
14390 ss << "'";
14391#ifdef FT_DUAL_SPEC
14392 ss << uint32_t(m_specs[SPEC_PRIMARY].getTalentPoints()) << " " << uint32_t(m_specs[SPEC_SECONDARY].getTalentPoints());
14393#else
14394 ss << uint32_t(m_spec.getTalentPoints()) << " 0";
14395#endif
14396 ss << "'" << ", ";
14397
14398#if VERSION_STRING < Cata
14399 ss << "'" << uint32_t(0) << "', ";
14400#else
14401 ss << "'" << uint32_t(m_FirstTalentTreeLock) << "', ";
14402#endif
14403
14404 ss << "'" << m_phase << "', ";
14405
14406 uint32_t xpfield = 0;
14407
14409 xpfield = 1;
14410
14411 ss << "'" << xpfield << "'" << ", ";
14412
14413 const bool saveData = worldConfig.server.saveExtendedCharData;
14414 if (saveData)
14415 {
14416 ss << "'";
14417 for (uint32_t offset = getSizeOfStructure(WoWObject); offset < getSizeOfStructure(WoWPlayer); offset++)
14418 ss << uint32_t(m_uint32Values[offset]) << ";";
14419 ss << "'" << ", ";
14420 }
14421 else
14422 {
14423 ss << "'', ";
14424 }
14425
14426 if (m_resetTalents)
14427 ss << uint32_t(1);
14428 else
14429 ss << uint32_t(0);
14430
14431 ss << ", ";
14432
14433 ss << uint32_t(this->hasWonRbgToday()) << ", " << uint32_t(m_dungeonDifficulty) << ", " << uint32_t(m_raidDifficulty);
14434 ss << ")";
14435
14436 if (newCharacter)
14437 CharacterDatabase.WaitExecuteNA(ss.str().c_str());
14438 else
14439 buf->AddQueryNA(ss.str().c_str());
14440
14441 // Save Other related player stuff
14442
14443 // Inventory
14444 getItemInterface()->mSaveItemsToDatabase(newCharacter, buf);
14445
14447
14448 // save quest progress
14450
14451 // Tutorials
14452 saveTutorials();
14453
14454 // GM Ticket
14455 //\todo Is this really necessary? Tickets will always be saved on creation, update and so on...
14456 GM_Ticket* ticket = sTicketMgr.getGMTicketByPlayer(getGuid());
14457 if (ticket != nullptr)
14458 sTicketMgr.saveGMTicket(ticket, buf);
14459
14460 // Cooldown Items
14462
14463 // Instance Timed Lockout
14465
14466 // Pets
14467 if (getClass() == HUNTER || getClass() == WARLOCK)
14468 {
14469 _savePet(buf, true);
14471 }
14473#if VERSION_STRING > TBC
14474 m_achievementMgr->saveToDb(buf);
14475#endif
14476
14477 if (buf)
14478 CharacterDatabase.AddQueryBuffer(std::move(bufPtr));
14479}
14480
14482{
14483 for (uint32_t removeableQuestId : m_removequests)
14484 {
14485 if (buf == nullptr)
14486 CharacterDatabase.Execute("DELETE FROM questlog WHERE player_guid=%u AND quest_id=%u", getGuidLow(), removeableQuestId);
14487 else
14488 buf->AddQuery("DELETE FROM questlog WHERE player_guid=%u AND quest_id=%u", getGuidLow(), removeableQuestId);
14489 }
14490
14491 m_removequests.clear();
14492
14493 for (auto& questlogEntry : m_questlog)
14494 {
14495 if (questlogEntry != nullptr)
14496 questlogEntry->saveToDB(buf);
14497 }
14498}
14499
14501{
14502 enum
14503 {
14509 Pets = 5,
14523}
14524
14526{
14527 auto q = std::make_unique<AsyncQuery>(std::make_unique<SQLClassCallbackP0<Player>>(this, &Player::loadFromDBProc));
14528
14529 q->AddQuery("SELECT * FROM characters WHERE guid = %u AND login_flags = %u", guid, (uint32_t)LOGIN_NO_FLAG); // 0
14530 q->AddQuery("SELECT * FROM tutorials WHERE playerId = %u", guid); // 1
14531 q->AddQuery("SELECT cooldown_type, cooldown_misc, cooldown_expire_time, cooldown_spellid, cooldown_itemid FROM playercooldowns WHERE player_guid = %u", guid); // 2
14532 q->AddQuery("SELECT * FROM questlog WHERE player_guid = %u", guid); // 3
14533 q->AddQuery("SELECT * FROM playeritems WHERE ownerguid = %u ORDER BY containerslot ASC", guid); // 4
14534 q->AddQuery("SELECT * FROM playerpets WHERE ownerguid = %u ORDER BY petnumber", guid); // 5
14535 q->AddQuery("SELECT * FROM playersummonspells where ownerguid = %u ORDER BY entryid", guid); // 6
14536 q->AddQuery("SELECT * FROM mailbox WHERE player_guid = %u", guid); // 7
14537
14538 // social
14539 q->AddQuery("SELECT friend_guid, note FROM social_friends WHERE character_guid = %u", guid); // 8
14540 q->AddQuery("SELECT character_guid FROM social_friends WHERE friend_guid = %u", guid); // 9
14541 q->AddQuery("SELECT ignore_guid FROM social_ignores WHERE character_guid = %u", guid); // 10
14542
14543
14544 q->AddQuery("SELECT * FROM equipmentsets WHERE ownerguid = %u", guid); // 11
14545 q->AddQuery("SELECT faction, flag, basestanding, standing FROM playerreputations WHERE guid = %u", guid); //12
14546 q->AddQuery("SELECT SpellID FROM playerspells WHERE GUID = %u", guid); // 13
14547 q->AddQuery("SELECT SpellID FROM playerdeletedspells WHERE GUID = %u", guid); // 14
14548 q->AddQuery("SELECT SkillID, CurrentValue, MaximumValue FROM playerskills WHERE GUID = %u", guid); // 15
14549
14550 //Achievements
14551 q->AddQuery("SELECT achievement, date FROM character_achievement WHERE guid = '%u'", guid); // 16
14552 q->AddQuery("SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", guid); // 17
14553
14554 // queue it!
14555 setGuidLow(guid);
14556 CharacterDatabase.QueueAsyncQuery(std::move(q));
14557 return true;
14558}
14559
14561{
14562 auto startTime = Util::TimeNow();
14563
14564 if (getSession() == nullptr || results.size() < 8) // should have 8 queryresults for aplayer load.
14565 {
14567 return;
14568 }
14569
14570 QueryResult* result = results[PlayerQuery::LoginFlags].result.get();
14571 if (!result)
14572 {
14573 sLogger.failure("Player login query failed! guid = {}", getGuidLow());
14575 return;
14576 }
14577
14578 const uint32_t fieldcount = 95;
14579 if (result->GetFieldCount() != fieldcount)
14580 {
14581 sLogger.failure("Expected {} fields from the database, but received {}! You may need to update your character database.", fieldcount, uint32_t(result->GetFieldCount()));
14583 return;
14584 }
14585
14586 Field* field = result->Fetch();
14587 if (field[1].asUint32() != m_session->GetAccountId())
14588 {
14589 sCheatLog.writefromsession(m_session, "player tried to load character not belonging to them (guid %u, on account %u)",
14590 field[0].asUint32(), field[1].asUint32());
14592 return;
14593 }
14594
14595 uint32_t banned = field[34].asUint32();
14596 if (banned && (banned < 100 || banned >(uint32_t)UNIXTIME))
14597 {
14599 return;
14600 }
14601
14602 m_name = field[2].asCString();
14603
14604 // Load race/class from fields
14605 setRace(field[3].asUint8());
14606 setClass(field[4].asUint8());
14607 setGender(field[5].asUint8());
14608 uint32_t cfaction = field[6].asUint32();
14609
14610 // set race dbc
14611 m_dbcRace = sChrRacesStore.lookupEntry(getRace());
14612 m_dbcClass = sChrClassesStore.lookupEntry(getClass());
14613 if (!m_dbcClass || !m_dbcRace)
14614 {
14615 // bad character
14616 sLogger.failure("guid {} failed to login, no race or class dbc found. (race {} class {})", getGuidLow(), (unsigned int)getRace(), (unsigned int)getClass());
14618 return;
14619 }
14620
14621 if (m_dbcRace->team_id == 7)
14622 m_bgTeam = m_team = 0;
14623 else
14624 m_bgTeam = m_team = 1;
14625
14627
14628 // set power type
14629 setPowerType(static_cast<uint8_t>(m_dbcClass->power_type));
14630
14631 // obtain player create m_playerCreateInfo
14632 m_playerCreateInfo = sMySQLStore.getPlayerCreateInfo(getRace(), getClass());
14633 if (m_playerCreateInfo == nullptr)
14634 {
14635 sLogger.failure("player guid {} has no playerCreateInfo!", getGuidLow());
14637 return;
14638 }
14639
14640 // set level
14641 setLevel(field[7].asUint32());
14642
14643 // obtain level/stats information
14644 m_levelInfo = sObjectMgr.getLevelInfo(getRace(), getClass(), getLevel());
14645
14646 if (!m_levelInfo)
14647 {
14648 sLogger.failure("guid {} level {} class {} race {} levelinfo not found!", getGuidLow(), getLevel(), (unsigned int)getClass(), (unsigned int)getRace());
14650 return;
14651 }
14652
14653#if VERSION_STRING > TBC
14654 // load achievements before anything else otherwise skills would complete achievements already in the DB, leading to duplicate achievements and criterias(like achievement=126).
14655 m_achievementMgr->loadFromDb(results[PlayerQuery::Achievements].result.get(), results[PlayerQuery::AchievementProgress].result.get());
14656#endif
14657
14659
14660 // set xp
14661 setXp(field[8].asUint32());
14662
14663 // Load active cheats
14664 uint32_t active_cheats = field[9].asUint32();
14665 if (active_cheats & PLAYER_CHEAT_COOLDOWN)
14667 if (active_cheats & PLAYER_CHEAT_CAST_TIME)
14669 if (active_cheats & PLAYER_CHEAT_GOD_MODE)
14671 if (active_cheats & PLAYER_CHEAT_POWER)
14672 m_cheats.hasPowerCheat = true;
14673 if (active_cheats & PLAYER_CHEAT_FLY)
14674 m_cheats.hasFlyCheat = true;
14675 if (active_cheats & PLAYER_CHEAT_AURA_STACK)
14677 if (active_cheats & PLAYER_CHEAT_ITEM_STACK)
14679 if (active_cheats & PLAYER_CHEAT_TRIGGERPASS)
14681 if (active_cheats & PLAYER_CHEAT_TAXI)
14682 m_cheats.hasTaxiCheat = true;
14683
14684 // Process exploration data.
14686
14687 loadSkills(results[PlayerQuery::Skills].result.get());
14688
14689 if (m_firstLogin || m_skills.empty())
14690 {
14691 // no skills - reset to defaults
14693 }
14694
14695#if VERSION_STRING >= Cata
14697#endif
14698
14699 // set the rest of the stuff
14700 setWatchedFaction(field[11].asUint32());
14701#if VERSION_STRING > Classic
14702 setChosenTitle(field[12].asUint32());
14703 setKnownTitles(0, field[13].asUint64());
14704#if VERSION_STRING > TBC
14705 setKnownTitles(1, field[14].asUint64());
14706 setKnownTitles(2, field[15].asUint64());
14707#endif
14708#endif
14709
14710 setCoinage(field[16].asUint32());
14711
14712#if VERSION_STRING < Cata
14713 setAmmoId(field[17].asUint32());
14714#endif
14715
14716 setFreePrimaryProfessionPoints(field[18].asUint32());
14717
14718 m_loadHealth = field[19].asUint32();
14719 m_loadMana = field[20].asUint32();
14721
14722 sLogger.debug("Player level {}, health {}, mana {} loaded from db!", getLevel(), m_loadHealth, m_loadMana);
14723
14724 setPvpRank(field[21].asUint8());
14725
14726 setPlayerBytes(field[22].asUint32());
14727 setPlayerBytes2(field[23].asUint32());
14728
14730
14731 setPlayerFlags(field[24].asUint32());
14732 setEnabledActionBars(field[25].asUint8());
14733
14734 m_position.x = field[26].asFloat();
14735 m_position.y = field[27].asFloat();
14736 m_position.z = field[28].asFloat();
14737 m_position.o = field[29].asFloat();
14738
14739 m_mapId = field[30].asUint32();
14740 m_zoneId = field[31].asUint32();
14742
14743 // Initialize 'normal' fields
14744 setScale(1.0f);
14745#if VERSION_STRING > TBC
14746 setHoverHeight(1.0f);
14747#endif
14748
14749 setBoundingRadius(0.388999998569489f);
14750 setCombatReach(1.5f);
14751
14753
14755
14756 if (const auto raceEntry = sChrRacesStore.lookupEntry(getRace()))
14757 setFaction(raceEntry->faction_id);
14758 else
14759 setFaction(0);
14760
14761 if (cfaction)
14762 {
14763 setFaction(cfaction);
14764 // re-calculate team
14765 switch (cfaction)
14766 {
14767 case 1: // human
14768 case 3: // dwarf
14769 case 4: // ne
14770 case 8: // gnome
14771 case 927: // draenei
14772 m_team = m_bgTeam = 0;
14773 break;
14774 case 2: // orc
14775 case 5: // undead
14776 case 6: // tauren
14777 case 9: // troll
14778 case 914: // bloodelf
14779 m_team = m_bgTeam = 1;
14780 break;
14781 }
14782 }
14783
14784 // Load Taxis From Database
14785 m_taxi->loadTaxiMask(field[32].asCString());
14787
14788 m_banned = field[33].asUint32(); //Character ban
14789 m_banreason = field[34].asCString();
14790 m_timeLogoff = field[35].asUint32();
14791 //field[36].GetUInt32(); online
14792
14793 setBindPoint(field[37].asFloat(), field[38].asFloat(), field[39].asFloat(), field[40].asFloat(), field[41].asUint32(), field[42].asUint32());
14794
14795 m_isResting = field[43].asUint8();
14796 m_restState = field[44].asUint8();
14797 m_restAmount = field[45].asUint32();
14798
14799
14800 std::string tmpStr = field[46].asCString();
14801 m_playedTime[0] = (uint32_t)atoi(strtok((char*)tmpStr.c_str(), " "));
14802 m_playedTime[1] = (uint32_t)atoi(strtok(nullptr, " "));
14803
14804 m_deathState = (DeathState)field[47].asUint32();
14805 m_talentResetsCount = field[48].asUint32();
14806 m_firstLogin = field[49].asBool();
14807 m_loginFlag = field[50].asUint32();
14808 m_arenaPoints = field[51].asUint32();
14809 if (m_arenaPoints > worldConfig.limit.maxArenaPoints)
14810 {
14811 std::stringstream dmgLog;
14812 dmgLog << "has over " << worldConfig.limit.maxArenaPoints << " arena points " << m_arenaPoints;
14813 sCheatLog.writefromsession(m_session, dmgLog.str().c_str());
14814
14815 if (worldConfig.limit.broadcastMessageToGmOnExceeding) // report to online GMs
14816 sendReportToGmMessage(getName(), dmgLog.str());
14817
14818 if (worldConfig.limit.disconnectPlayerForExceedingLimits)
14819 {
14821 }
14822 m_arenaPoints = worldConfig.limit.maxArenaPoints;
14823 }
14824
14826
14828
14829 m_stableSlotCount = static_cast<uint8_t>(field[52].asUint32());
14830 m_instanceId = field[53].asUint32();
14831
14832 setBGEntryPoint(field[55].asFloat(), field[56].asFloat(), field[57].asFloat(), field[58].asFloat(), field[54].asUint32(), field[59].asUint32());
14833
14834 std::string taxi_nodes = field[60].asCString();
14835 uint32_t taxi_currentNode = field[61].asInt32();
14836
14837 uint32_t transportGuid = field[62].asUint32();
14838 float transportX = field[63].asFloat();
14839 float transportY = field[64].asFloat();
14840 float transportZ = field[65].asFloat();
14841 float transportO = field[66].asFloat();
14842
14843 if (transportGuid != 0)
14844 obj_movement_info.setTransportData(transportGuid, transportX, transportY, transportZ, transportO, 0, 0);
14845 else
14847
14848 loadDeletedSpells(results[PlayerQuery::DeletedSpells].result.get());
14849
14850 loadSpells(results[PlayerQuery::Spells].result.get());
14851
14852 loadReputations(results[PlayerQuery::Reputation].result.get());
14853
14854 // Load saved actionbars
14855 uint32_t Counter = 0;
14856 char* start = nullptr;
14857 char* end = nullptr;
14858#if VERSION_STRING > TBC
14859 for (uint8_t s = 0; s < MAX_SPEC_COUNT; ++s)
14860 {
14861 start = (char*)field[67 + s].asCString();
14862 Counter = 0;
14863 while (Counter < PLAYER_ACTION_BUTTON_COUNT)
14864 {
14865 if (start == nullptr)
14866 break;
14867
14868 end = strchr(start, ',');
14869 if (!end)
14870 break;
14871 *end = 0;
14872 m_specs[0 + s].getActionButton(Counter).Action = std::stoul(start);
14873 start = end + 1;
14874 end = strchr(start, ',');
14875 if (!end)
14876 break;
14877 *end = 0;
14878 m_specs[0 + s].getActionButton(Counter).Type = static_cast<uint8_t>(std::stoul(start));
14879 start = end + 1;
14880 end = strchr(start, ',');
14881 if (!end)
14882 break;
14883 *end = 0;
14884 m_specs[0 + s].getActionButton(Counter).Misc = static_cast<uint8_t>(std::stoul(start));
14885 start = end + 1;
14886
14887 Counter++;
14888 }
14889 }
14890#else
14891 {
14892 auto& spec = m_spec;
14893
14894 start = (char*)field[67].asCString();
14895 Counter = 0;
14896 while (Counter < PLAYER_ACTION_BUTTON_COUNT)
14897 {
14898 if (start == nullptr)
14899 break;
14900
14901 end = strchr(start, ',');
14902 if (!end)
14903 break;
14904 *end = 0;
14905 spec.getActionButton(Counter).Action = (uint32_t)std::stoul(start);
14906 start = end + 1;
14907 end = strchr(start, ',');
14908 if (!end)
14909 break;
14910 *end = 0;
14911 spec.getActionButton(Counter).Type = (uint8_t)std::stoul(start);
14912 start = end + 1;
14913 end = strchr(start, ',');
14914 if (!end)
14915 break;
14916 *end = 0;
14917 spec.getActionButton(Counter).Misc = (uint8_t)std::stoul(start);
14918 start = end + 1;
14919
14920 Counter++;
14921 }
14922 }
14923#endif
14924
14925 if (m_firstLogin)
14926 {
14927 for (const auto itr : m_playerCreateInfo->actionbars)
14928 setActionButton(itr.button, itr.action, itr.type, itr.misc);
14929 }
14930
14931 //////////////////////////////////////////////////////////////////////////////////////////
14932 // Parse saved buffs
14933 std::istringstream savedPlayerBuffsStream(field[69].asCString());
14934 std::string auraId, auraDuration, auraPositivValue, auraCharges;
14935
14936 while (std::getline(savedPlayerBuffsStream, auraId, ','))
14937 {
14938 LoginAura la;
14939 la.id = std::stoul(auraId.c_str());
14940
14941 std::getline(savedPlayerBuffsStream, auraDuration, ',');
14942 la.dur = std::stoul(auraDuration.c_str());
14943
14944 std::getline(savedPlayerBuffsStream, auraPositivValue, ',');
14945 la.positive = auraPositivValue.empty() ? false : true;
14946
14947 std::getline(savedPlayerBuffsStream, auraCharges, ',');
14948 la.charges = std::stoul(auraCharges.c_str());
14949
14950 m_loginAuras.push_back(la);
14951 }
14952
14953 // Load saved finished quests
14954
14955 start = (char*)field[70].asCString();
14956 while (true)
14957 {
14958 end = strchr(start, ',');
14959 if (!end)break;
14960 *end = 0;
14961 const uint32_t questEntry = std::stoul(start);
14962 m_finishedQuests.insert(questEntry);
14963
14964 // Load talent points from finished quests
14965 auto questProperties = sMySQLStore.getQuestProperties(questEntry);
14966 if (questProperties != nullptr && questProperties->rewardtalents > 0)
14967 m_talentPointsFromQuests += questProperties->rewardtalents;
14968
14969 start = end + 1;
14970 }
14971
14972 start = (char*)field[71].asCString();
14973 while (true)
14974 {
14975 end = strchr(start, ',');
14976 if (!end) break;
14977 *end = 0;
14978 m_finishedDailies.insert(std::stoul(start));
14979 start = end + 1;
14980 }
14981
14982 m_honorRolloverTime = field[72].asUint32();
14983 m_killsToday = field[73].asUint32();
14984 m_killsYesterday = field[74].asUint32();
14985 m_killsLifetime = field[75].asUint32();
14986
14987 m_honorToday = field[76].asUint32();
14988 m_honorYesterday = field[77].asUint32();
14989 m_honorPoints = field[78].asUint32();
14990 if (m_honorPoints > worldConfig.limit.maxHonorPoints)
14991 {
14992 std::stringstream dmgLog;
14993 dmgLog << "has over " << worldConfig.limit.maxHonorPoints << " honor points " << m_honorPoints;
14994
14995 sCheatLog.writefromsession(m_session, dmgLog.str().c_str());
14996
14997 if (worldConfig.limit.broadcastMessageToGmOnExceeding)
14998 sendReportToGmMessage(getName(), dmgLog.str());
14999
15000 if (worldConfig.limit.disconnectPlayerForExceedingLimits)
15002
15003 m_honorPoints = worldConfig.limit.maxHonorPoints;
15004 }
15005
15006 rolloverHonor();
15007
15008 // Load drunk value and calculate sobering. after 15 minutes logged out, the player will be sober again
15009 uint32_t timediff = (uint32_t)UNIXTIME - m_timeLogoff;
15010 uint32_t soberFactor;
15011 if (timediff > 900)
15012 soberFactor = 0;
15013 else
15014 soberFactor = 1 - timediff / 900;
15015
15016 setServersideDrunkValue(uint16_t(soberFactor * field[79].asUint32()));
15017
15018#if VERSION_STRING > TBC
15019 for (uint8_t s = 0; s < MAX_SPEC_COUNT; ++s)
15020 {
15021 start = (char*)field[80 + 2 * s].asCString();
15022 uint8_t glyphid = 0;
15023 while (glyphid < GLYPHS_COUNT)
15024 {
15025 end = strchr(start, ',');
15026 if (!end)break;
15027 *end = 0;
15028 m_specs[s].setGlyph(static_cast<uint16_t>(std::stoul(start)), glyphid);
15029 ++glyphid;
15030 start = end + 1;
15031 }
15032
15033 //Load talents for spec
15034 start = (char*)field[81 + 2 * s].asCString();
15035 while (end != nullptr)
15036 {
15037 end = strchr(start, ',');
15038 if (!end)
15039 break;
15040 *end = 0;
15041 uint32_t talentid = std::stoul(start);
15042 start = end + 1;
15043
15044 end = strchr(start, ',');
15045 if (!end)
15046 break;
15047 *end = 0;
15048 uint8_t rank = static_cast<uint8_t>(std::stoul(start));
15049 start = end + 1;
15050
15051 m_specs[s].addTalent(talentid, rank);
15052 }
15053 }
15054#else
15055 {
15056 auto& spec = m_spec;
15057
15058 //Load talents for spec
15059 start = (char*)field[81].asCString(); // talents1
15060 while (end != nullptr)
15061 {
15062 end = strchr(start, ',');
15063 if (!end)
15064 break;
15065 *end = 0;
15066 uint32_t talentid = std::stoul(start);
15067 start = end + 1;
15068
15069 end = strchr(start, ',');
15070 if (!end)
15071 break;
15072 *end = 0;
15073 uint8_t rank = static_cast<uint8_t>(std::stoul(start));
15074 start = end + 1;
15075
15076 spec.addTalent(talentid, rank);
15077 }
15078 }
15079#endif
15080
15081 m_talentSpecsCount = field[84].asUint8();
15082 m_talentActiveSpec = field[85].asUint8();
15083
15084#if VERSION_STRING > TBC
15085 {
15086 if (auto talentPoints = field[86].asCString())
15087 {
15088 uint32_t tps[2] = { 0,0 };
15089
15090 auto talentPointsVector = AscEmu::Util::Strings::split(talentPoints, " ");
15091 for (uint8_t i = 0; i < 2; ++i)
15092 tps[i] = std::stoi(talentPointsVector[i]);
15093
15094 m_specs[SPEC_PRIMARY].setTalentPoints(tps[0]);
15095 m_specs[SPEC_SECONDARY].setTalentPoints(tps[1]);
15096 }
15097#if VERSION_STRING < Cata
15098 setFreeTalentPoints(getActiveSpec().getTalentPoints());
15099#endif
15100 }
15101#else
15102 {
15103 if (auto talentPoints = field[86].asCString())
15104 {
15105 uint32_t tps[2] = { 0,0 };
15106
15107 auto talentPointsVector = AscEmu::Util::Strings::split(talentPoints, " ");
15108 for (uint8_t i = 0; i < 2; ++i)
15109 tps[i] = std::stoi(talentPointsVector[i]);
15110
15111 m_spec.setTalentPoints(tps[0]);
15112 }
15113
15114 setFreeTalentPoints(getActiveSpec().getTalentPoints());
15115 }
15116#endif
15117
15118#if VERSION_STRING >= Cata
15119 m_FirstTalentTreeLock = field[87].asUint32(); // Load First Set Talent Tree
15120#endif
15121
15122 m_phase = field[88].asUint32(); //Load the player's last phase
15123
15124 uint32_t xpfield = field[89].asUint32();
15125
15126 if (xpfield == 0)
15127 m_isXpGainAllowed = false;
15128 else
15129 m_isXpGainAllowed = true;
15130
15131 //field[90].GetString(); //skipping data
15132
15133 if (field[91].asUint32() == 1)
15134 m_resetTalents = true;
15135 else
15136 m_resetTalents = false;
15137
15138 // Load player's RGB daily data
15139 if (field[92].asUint32() == 1)
15140 m_hasWonRbgToday = true;
15141 else
15142 m_hasWonRbgToday = false;
15143
15144 m_dungeonDifficulty = field[93].asUint8();
15145 m_raidDifficulty = field[94].asUint8();
15146
15148
15149#if VERSION_STRING > TBC
15150 updateGlyphs();
15151
15152 for (uint8_t i = 0; i < GLYPHS_COUNT; ++i)
15153 setGlyph(i, m_specs[m_talentActiveSpec].getGlyph(i));
15154#endif
15155
15156 //class fixes
15157 switch (getClass())
15158 {
15159 case WARLOCK:
15160 case HUNTER:
15161#if VERSION_STRING >= WotLK
15162 case DEATHKNIGHT:
15163 case MAGE:
15164#endif
15165 _loadPet(results[PlayerQuery::Pets].result.get());
15166 _loadPetSpells(results[PlayerQuery::SummonSpells].result.get());
15167 break;
15168 }
15169
15170 if (getGuildId())
15171 setGuildTimestamp(static_cast<uint32_t>(UNIXTIME));
15172
15173 // load properties
15174 loadTutorials();
15175 _loadPlayerCooldowns(results[PlayerQuery::Cooldowns].result.get());
15176 _loadQuestLogEntry(results[PlayerQuery::Questlog].result.get());
15179
15180#if VERSION_STRING > WotLK
15181 loadVoidStorage();
15182#endif
15183
15184 m_mailBox->Load(results[PlayerQuery::Mailbox].result.get());
15185
15186 // Saved Instances
15189
15190 // Create Instance when needed
15191 if (sMapMgr.findBaseMap(GetMapId()) && sMapMgr.findBaseMap(GetMapId())->isInstanceableMap())
15192 {
15193 // No Instance Found Lets Create it
15194 if (!sMapMgr.findWorldMap(GetMapId(), GetInstanceID()))
15195 sMapMgr.createInstanceForPlayer(GetMapId(), this, GetInstanceID());
15196 }
15197
15198 // SOCIAL
15202 // END SOCIAL
15203
15204 // Check skills that player shouldn't have
15207
15208#if VERSION_STRING > TBC
15209 // update achievements before adding player to World, otherwise we'll get a nice race condition.
15210 //move CheckAllAchievementCriteria() after FullLogin(this) and i'll cut your b***s.
15211 m_achievementMgr->updateAllAchievementCriteria();
15212#endif
15213
15214 m_session->fullLogin(this);
15215 m_session->m_loggingInPlayer = nullptr;
15216
15217 if (!isAlive())
15218 {
15219 if (const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow()))
15220 setCorpseData(corpse->GetPosition(), corpse->GetInstanceID());
15221 }
15222
15223#if VERSION_STRING > Classic
15224 uint32_t uniques[64];
15225 int nuniques = 0;
15226
15228 {
15230 Item* it = itemi->GetInventoryItem(x);
15231
15232 if (it != nullptr)
15233 {
15234 for (uint8_t count = 0; count < it->getSocketSlotCount(); count++)
15235 {
15236 const auto enchantmentSlot = static_cast<EnchantmentSlot>(SOCK_ENCHANTMENT_SLOT1 + count);
15237 EnchantmentInstance* ei = it->getEnchantment(enchantmentSlot);
15238
15239 if (ei && ei->Enchantment)
15240 {
15241 ItemProperties const* ip = sMySQLStore.getItemProperties(ei->Enchantment->GemEntry);
15242
15243 if (ip && ip->Flags & ITEM_FLAG_UNIQUE_EQUIP &&
15244 itemi->IsEquipped(ip->ItemId))
15245 {
15246 int i;
15247
15248 for (i = 0; i < nuniques; i++)
15249 {
15250 if (uniques[i] == ip->ItemId)
15251 {
15252 // found a duplicate unique-equipped gem, remove it
15253 it->removeEnchantment(enchantmentSlot);
15254 break;
15255 }
15256 }
15257
15258 if (i == nuniques) // not found
15259 uniques[nuniques++] = ip->ItemId;
15260 }
15261 }
15262 }
15263 }
15264 }
15265#endif
15266
15267 // Continue Our Taxi Path
15268 if (!taxi_nodes.empty())
15269 {
15270 // Not finish taxi flight path
15271 if (!m_taxi->loadTaxiDestinationsFromString(taxi_nodes, GetTeam()))
15272 {
15273 // problems with taxi path loading
15274 WDB::Structures::TaxiNodesEntry const* nodeEntry = nullptr;
15275 if (uint32_t node_id = m_taxi->getTaxiSource())
15276 nodeEntry = sTaxiNodesStore.lookupEntry(node_id);
15277
15278 if (!nodeEntry) // don't know taxi start node, teleport to homebind
15279 {
15281 }
15282 else // has start node, teleport to it
15283 {
15284 safeTeleport(nodeEntry->mapid, 0, LocationVector(nodeEntry->x, nodeEntry->y, nodeEntry->z, 0.0f));
15285 }
15286 m_taxi->clearTaxiDestinations();
15287 }
15288
15289 m_taxi->setNodeAfterTeleport(taxi_currentNode);
15290 // flight will started later
15291 }
15292
15293 auto timeToNow = Util::GetTimeDifferenceToNow(startTime);
15294 sLogger.info("Time for playerloading: {} ms", static_cast<uint32_t>(timeToNow));
15295}
15296
15298{
15299 for (uint8_t slot = 0; slot < MAX_QUEST_SLOT; ++slot)
15300 {
15301 setQuestLogEntryBySlot(slot, 0);
15302 setQuestLogStateBySlot(slot, 0);
15305 }
15306
15307 if (result)
15308 {
15309 do
15310 {
15311 Field* fields = result->Fetch();
15312 uint32_t questid = fields[1].asUint32();
15313 uint8_t slot = fields[2].asUint8();
15314
15315 QuestProperties const* questProperties = sMySQLStore.getQuestProperties(questid);
15316 if (!questProperties)
15317 {
15318 m_removequests.insert(questid);
15319 continue;
15320 }
15321
15322 if (m_questlog[slot] != nullptr)
15323 continue;
15324
15325 auto* questLogEntry = createQuestLogInSlot(questProperties, slot);
15326 questLogEntry->loadFromDB(fields);
15327 questLogEntry->updatePlayerFields();
15328
15329 } while (result->NextRow());
15330 }
15331}
15332
15333#if VERSION_STRING >= TBC
15335{
15336 float chance = getSkillLineCurrent(SKILL_DEFENSE, true) - (opLevel * 5.0f);
15337 chance += calcRating(CR_DEFENSE_SKILL);
15338 chance = floorf(chance) * 0.04f; // defense skill is treated as an integer on retail
15339
15340 return chance;
15341}
15342
15344{
15345 const float crit_to_dodge[MAX_PLAYER_CLASSES] =
15346 {
15347 0.0f, // empty
15348 1.1f, // Warrior
15349 1.0f, // Paladin
15350 1.6f, // Hunter
15351 2.0f, // Rogue
15352 1.0f, // Priest
15353 1.0f, // DK?
15354 1.0f, // Shaman
15355 1.0f, // Mage
15356 1.0f, // Warlock
15357 0.0f, // empty
15358 1.7f // Druid
15359 };
15360
15361 uint32_t playerClass = getClass();
15362 float chance = 0.0f;
15363 uint32_t level = getLevel();
15364
15365 if (level > worldConfig.player.playerGeneratedInformationByLevelCap)
15366 level = worldConfig.player.playerGeneratedInformationByLevelCap;
15367
15368 // Base dodge + dodge from agility
15369 auto baseCrit = sGtChanceToMeleeCritBaseStore.lookupEntry(playerClass - 1);
15370 auto critPerAgi = sGtChanceToMeleeCritStore.lookupEntry(level - 1 + (playerClass - 1) * 100);
15372
15373 float tmp = 100.0f * (baseCrit->val + agi * critPerAgi->val);
15374 tmp *= crit_to_dodge[playerClass];
15375 chance += tmp;
15376
15377 chance += calcRating(CR_DODGE);
15378 chance += getDodgeFromSpell();
15379
15380 return std::max(chance, 0.0f); // Make sure we don't have a negative chance
15381}
15382
15384{
15385 float chance = BASE_BLOCK_CHANCE;
15386 chance += calcRating(CR_BLOCK);
15387 chance += getBlockFromSpell();
15388
15389 return std::max(chance, 0.0f); // Make sure we don't have a negative chance
15390}
15391
15393{
15394 float chance = BASE_PARRY_CHANCE;
15395 chance += calcRating(CR_PARRY);
15396 chance += getParryFromSpell();
15397
15398 return std::max(chance, 0.0f); // Make sure we don't have a negative chance
15399}
15400
15402{
15403 uint32_t playerClass = getClass();
15405
15406 float tmp = 0;
15407 float defence_contribution = 0;
15408
15409 // Avoidance from defense skill
15410 defence_contribution = getDefenseChance(playerLevel);
15411
15412 // Dodge
15413 tmp = getDodgeChance();
15414 tmp += defence_contribution;
15415 tmp = std::min(std::max(tmp, 0.0f), 95.0f);
15416 setDodgePercentage(tmp);
15417
15418 // Block
15420 if (it != nullptr && it->getItemProperties()->InventoryType == INVTYPE_SHIELD)
15421 {
15422 tmp = getBlockChance();
15423 tmp += defence_contribution;
15424 tmp = std::min(std::max(tmp, 0.0f), 95.0f);
15425 }
15426 else
15427 {
15428 tmp = 0.0f;
15429 }
15430
15431 setBlockPercentage(tmp);
15432
15433 // Parry (can only parry with something in main hand)
15435 if (it != nullptr)
15436 {
15437 tmp = getParryChance();
15438 tmp += defence_contribution;
15439 tmp = std::min(std::max(tmp, 0.0f), 95.0f);
15440 }
15441 else
15442 {
15443 tmp = 0.0f;
15444 }
15445
15446 setParryPercentage(tmp);
15447
15448 // Critical
15449 auto baseCrit = sGtChanceToMeleeCritBaseStore.lookupEntry(playerClass - 1);
15450
15451 auto CritPerAgi = sGtChanceToMeleeCritStore.lookupEntry(playerLevel - 1 + (playerClass - 1) * 100);
15452 if (CritPerAgi == nullptr)
15453 CritPerAgi = sGtChanceToMeleeCritStore.lookupEntry(DBC_PLAYER_LEVEL_CAP - 1 + (playerClass - 1) * 100);
15454
15455 tmp = 100 * (baseCrit->val + getStat(STAT_AGILITY) * CritPerAgi->val);
15456
15457 float melee_bonus = 0;
15458 float ranged_bonus = 0;
15459
15460 if (m_toCritChance.size() > 0)
15461 {
15464
15465 //-1 = any weapon
15466 for (std::map< uint32_t, WeaponModifier >::iterator itr = m_toCritChance.begin(); itr != m_toCritChance.end(); ++itr)
15467 {
15468 if (itr->second.wclass == (uint32_t)-1 || (tItemMelee != nullptr && (1 << tItemMelee->getItemProperties()->SubClass & itr->second.subclass)))
15469 melee_bonus += itr->second.value;
15470
15471 if (itr->second.wclass == (uint32_t)-1 || (tItemRanged != nullptr && (1 << tItemRanged->getItemProperties()->SubClass & itr->second.subclass)))
15472 ranged_bonus += itr->second.value;
15473 }
15474 }
15475
15476 float cr = tmp + calcRating(CR_CRIT_MELEE) + melee_bonus;
15477 setMeleeCritPercentage(std::min(cr, 95.0f));
15478
15479 float rcr = tmp + calcRating(CR_CRIT_RANGED) + ranged_bonus;
15480 setRangedCritPercentage(std::min(rcr, 95.0f));
15481
15482 auto SpellCritBase = sGtChanceToSpellCritBaseStore.lookupEntry(playerClass - 1);
15483
15484 auto SpellCritPerInt = sGtChanceToSpellCritStore.lookupEntry(playerLevel - 1 + (playerClass - 1) * 100);
15485 if (SpellCritPerInt == nullptr)
15486 SpellCritPerInt = sGtChanceToSpellCritStore.lookupEntry(DBC_PLAYER_LEVEL_CAP - 1 + (playerClass - 1) * 100);
15487
15488 m_spellCritPercentage = 100 * (SpellCritBase->val + getStat(STAT_INTELLECT) * SpellCritPerInt->val) +
15489 this->getSpellCritFromSpell() +
15491
15493}
15494#endif
15495
15497{
15498#if VERSION_STRING != Classic
15499 for (uint8_t school = 0; school < 7; ++school)
15501#endif
15502}
15503
15505{
15506 uint32_t speed = 2000;
15507
15508 if (getShapeShiftForm() == FORM_CAT)
15509 speed = 1000;
15511 speed = 2500;
15512 else if (!m_isDisarmed)
15513 if (const auto* itemWeapon = getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND))
15514 speed = itemWeapon->getItemProperties()->Delay;
15515
15516 setBaseAttackTime(MELEE, static_cast<uint32_t>(static_cast<float>(speed) / (getAttackSpeedModifier(MELEE) * (1.0f + calcRating(CR_HASTE_MELEE) / 100.0f))));
15517
15518 const auto* offhandWeapon = getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
15519 if (offhandWeapon && offhandWeapon->getItemProperties()->Class == ITEM_CLASS_WEAPON)
15520 {
15521 speed = offhandWeapon->getItemProperties()->Delay;
15522 setBaseAttackTime(OFFHAND, static_cast<uint32_t>(static_cast<float>(speed) / (getAttackSpeedModifier(OFFHAND) * (1.0f + calcRating(CR_HASTE_MELEE) / 100.0f))));
15523 }
15524
15525 if (const auto* rangedWeapon = getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED))
15526 {
15527 speed = rangedWeapon->getItemProperties()->Delay;
15528 setBaseAttackTime(RANGED, static_cast<uint32_t>(static_cast<float>(speed) / (getAttackSpeedModifier(RANGED) * (1.0f + calcRating(CR_HASTE_RANGED) / 100.0f))));
15529 }
15530}
15531
15533{
15535
15536 // Formulas from wowwiki
15537 int32_t attackPower = 0;
15538 int32_t rangedAttackPower = 0;
15539 int32_t hpdelta = 128;
15540 int32_t manadelta = 128;
15541
15544 uint32_t lev = getLevel();
15545
15546 // Attack power
15547 uint32_t playerClass = getClass();
15548 switch (playerClass)
15549 {
15550 case DRUID:
15551 //(Strength x 2) - 20
15552 attackPower = str * 2 - 20;
15553 //Agility - 10
15554 rangedAttackPower = agi - 10;
15555
15557 {
15558 //(Strength x 2) + (Character Level x 1.5) - 20
15559 attackPower += Util::float2int32(static_cast<float>(lev) * 1.5f);
15560 }
15561 if (getShapeShiftForm() == FORM_CAT)
15562 {
15563 //(Strength x 2) + Agility + (Character Level x 2) - 20
15564 attackPower += agi + (lev * 2);
15565 }
15567 {
15568 //(Strength x 2) + (Character Level x 3) - 20
15569 attackPower += (lev * 3);
15570 }
15571 break;
15572
15573 case ROGUE:
15574 //Strength + Agility + (Character Level x 2) - 20
15575 attackPower = str + agi + (lev * 2) - 20;
15576 //Character Level + Agility - 10
15577 rangedAttackPower = lev + agi - 10;
15578
15579 break;
15580
15581 case HUNTER:
15582 //Strength + Agility + (Character Level x 2) - 20
15583 attackPower = str + agi + (lev * 2) - 20;
15584 //(Character Level x 2) + Agility - 10
15585 rangedAttackPower = (lev * 2) + agi - 10;
15586
15587 break;
15588
15589 case SHAMAN:
15590 //(Strength) + (Agility) + (Character Level x 2) - 20
15591 attackPower = str + agi + (lev * 2) - 20;
15592 //Agility - 10
15593 rangedAttackPower = agi - 10;
15594
15595 break;
15596
15597 case PALADIN:
15598 //(Strength x 2) + (Character Level x 3) - 20
15599 attackPower = (str * 2) + (lev * 3) - 20;
15600 //Agility - 10
15601 rangedAttackPower = agi - 10;
15602
15603 break;
15604
15605 case WARRIOR:
15606#if VERSION_STRING >= WotLK
15607 case DEATHKNIGHT:
15608 //(Strength x 2) + (Character Level x 3) - 20
15609 attackPower = (str * 2) + (lev * 3) - 20;
15610 //Character Level + Agility - 10
15611 rangedAttackPower = lev + agi - 10;
15612
15613 break;
15614#endif
15615 default: //mage,priest,warlock
15616 attackPower = agi - 10;
15617 }
15618
15619 /* modifiers */
15620 rangedAttackPower += m_rapModPct * getStat(STAT_INTELLECT) / 100;
15621
15622 if (rangedAttackPower < 0)
15623 rangedAttackPower = 0;
15624
15625 if (attackPower < 0)
15626 attackPower = 0;
15627
15628 setAttackPower(attackPower);
15629 setRangedAttackPower(rangedAttackPower);
15630
15631 const auto* levelInfo = sObjectMgr.getLevelInfo(this->getRace(), this->getClass(), lev);
15632 if (levelInfo != nullptr)
15633 {
15634 hpdelta = levelInfo->Stat[2] * 10;
15635 manadelta = levelInfo->Stat[3] * 15;
15636 }
15637
15638 levelInfo = sObjectMgr.getLevelInfo(this->getRace(), this->getClass(), 1);
15639 if (levelInfo != nullptr)
15640 {
15641 hpdelta -= levelInfo->Stat[2] * 10;
15642 manadelta -= levelInfo->Stat[3] * 15;
15643 }
15644
15645 uint32_t hp = getBaseHealth();
15646
15647#if VERSION_STRING != Classic
15648 int32_t stat_bonus = getPosStat(STAT_STAMINA) - getNegStat(STAT_STAMINA);
15649#else
15650 int32_t stat_bonus = 0;
15651#endif
15652 if (stat_bonus < 0)
15653 stat_bonus = 0; // Avoid of having negative health
15654 int32_t bonus = stat_bonus * 10 + m_healthFromSpell + m_healthFromItems;
15655
15656 uint32_t res = hp + bonus + hpdelta;
15657 uint32_t oldmaxhp = getMaxHealth();
15658
15659 if (res < hp)
15660 res = hp;
15661
15662 if (worldConfig.limit.isLimitSystemEnabled && (worldConfig.limit.maxHealthCap > 0) && (res > worldConfig.limit.maxHealthCap) && !getSession()->hasPermissions()) //hacker?
15663 {
15664 std::stringstream dmgLog;
15665 dmgLog << "has over " << worldConfig.limit.maxArenaPoints << " health " << res;
15666
15667 sCheatLog.writefromsession(getSession(), dmgLog.str().c_str());
15668
15669 if (worldConfig.limit.broadcastMessageToGmOnExceeding)
15670 sendReportToGmMessage(getName(), dmgLog.str());
15671
15672 if (worldConfig.limit.disconnectPlayerForExceedingLimits)
15674 else // no disconnect, set it to the cap instead
15675 res = worldConfig.limit.maxHealthCap;
15676 }
15677 setMaxHealth(res);
15678
15679 if (getHealth() > res)
15680 {
15681 setHealth(res);
15682 }
15683 else if (playerClass == DRUID && (getShapeShiftForm() == FORM_BEAR || getShapeShiftForm() == FORM_DIREBEAR))
15684 {
15685 res = getMaxHealth() * getHealth() / oldmaxhp;
15686 setHealth(res);
15687 }
15688
15689 if (playerClass != WARRIOR && playerClass != ROGUE
15690#if VERSION_STRING > TBC
15691 && playerClass != DEATHKNIGHT
15692#endif
15693 )
15694 {
15695 // MP
15696 uint32_t mana = getBaseMana();
15697#if VERSION_STRING != Classic
15698 stat_bonus = getPosStat(STAT_INTELLECT) - getNegStat(STAT_INTELLECT);
15699#endif
15700 if (stat_bonus < 0)
15701 stat_bonus = 0; // Avoid of having negative mana
15702 bonus = stat_bonus * 15 + m_manaFromSpell + m_manaFromItems;
15703
15704 res = mana + bonus + manadelta;
15705 if (res < mana)
15706 res = mana;
15707
15708 if (worldConfig.limit.isLimitSystemEnabled && (worldConfig.limit.maxManaCap > 0) && (res > worldConfig.limit.maxManaCap) && !getSession()->hasPermissions()) //hacker?
15709 {
15710 char logmsg[256];
15711 snprintf(logmsg, 256, "has over %u mana (%i)", worldConfig.limit.maxManaCap, res);
15712 sCheatLog.writefromsession(getSession(), logmsg);
15713
15714 if (worldConfig.limit.broadcastMessageToGmOnExceeding) // send m_playerCreateInfo to online GM
15715 sendReportToGmMessage(getName(), logmsg);
15716
15717 if (worldConfig.limit.disconnectPlayerForExceedingLimits)
15719 else // no disconnect, set it to the cap instead
15720 res = worldConfig.limit.maxManaCap;
15721 }
15723
15724 if (getPower(POWER_TYPE_MANA) > res)
15726
15728 }
15729
15730 // Spell haste rating
15731 float haste = 1.0f + calcRating(CR_HASTE_SPELL) / 100.0f;
15732 if (haste != m_spellHasteRatingBonus)
15733 {
15734 float value = getModCastSpeed() * m_spellHasteRatingBonus / haste; // remove previous mod and apply current
15735
15737 m_spellHasteRatingBonus = haste; // keep value for next run
15738 }
15739
15740 // Shield Block
15742 if (itemShield != nullptr && itemShield->getItemProperties()->InventoryType == INVTYPE_SHIELD)
15743 {
15744 float block_multiplier = (100.0f + m_modBlockAbsorbValue) / 100.0f;
15745 if (block_multiplier < 1.0f)
15746 block_multiplier = 1.0f;
15747
15748 int32_t blockable_damage = Util::float2int32((itemShield->getItemProperties()->Block + m_modBlockValueFromSpells + getCombatRating(CR_BLOCK) + (str / 2.0f) - 1.0f) * block_multiplier);
15749#if VERSION_STRING != Classic
15750 setShieldBlock(blockable_damage);
15751#endif
15752 }
15753 else
15754 {
15755#if VERSION_STRING != Classic
15756 setShieldBlock(0);
15757#endif
15758 }
15759
15760 // Dynamic aura application, auras 212, 268
15761#if VERSION_STRING >= WotLK
15763 aurEff->getAura()->updateModifiers();
15764#endif
15765#if VERSION_STRING >= TBC
15767 aurEff->getAura()->updateModifiers();
15768
15769 updateChances();
15770#endif
15771
15773}
15774
15776{
15778}
15779
15781{
15782 if (object == nullptr)
15783 return;
15784
15785 if (isVisibleObject(object->getGuid()))
15786 {
15788 }
15789
15790 m_visibleObjects.erase(object->getGuid());
15792
15793 if (object->getGuid() == getCharmGuid())
15794 {
15795 Unit* unit = getWorldMap()->getUnit(getCharmGuid());
15796 if (!unit)
15797 return;
15798
15799 unPossess();
15800
15801 if (isCastingSpell())
15803
15804 setCharmGuid(0);
15805 }
15806}
15807
15809{
15810 m_visibleObjects.clear();
15812}
15813
15815{
15816 if (getChannelSpellId() != 20577)
15817 {
15818 sEventMgr.RemoveEvents(this, EVENT_CANNIBALIZE);
15819 m_cannibalize = false;
15821 return;
15822 }
15823
15824 uint32_t amt = (getMaxHealth() * amount) / 100;
15825
15826 uint32_t newHealth = getHealth() + amt;
15827 if (newHealth <= getMaxHealth())
15828 setHealth(newHealth);
15829 else
15831
15833 if (m_cannibalizeCount == 5)
15835
15836 sendPeriodicAuraLog(GetNewGUID(), GetNewGUID(), sSpellMgr.getSpellInfo(20577), amt, 0, 0, 0, SPELL_AURA_PERIODIC_HEAL_PCT, false);
15837}
15838
15840{
15841 if (type < 7)
15842 {
15843 int32_t pos = (m_baseResistance[type] * m_baseResistanceModPctPos[type]) / 100;
15844 int32_t neg = (m_baseResistance[type] * m_baseResistanceModPctNeg[type]) / 100;
15845
15846 pos += m_flatResistanceModifierPos[type];
15848 int32_t res = m_baseResistance[type] + pos - neg;
15849
15850 if (type == 0)
15851 res += getStat(STAT_AGILITY) * 2; //fix armor from agi
15852
15853 if (res < 0)
15854 res = 0;
15855
15856 pos += (res * m_resistanceModPctPos[type]) / 100;
15857 neg += (res * m_resistanceModPctNeg[type]) / 100;
15858 res = pos - neg + m_baseResistance[type];
15859
15860 if (type == 0)
15861 res += getStat(STAT_AGILITY) * 2; //fix armor from agi
15862
15863#if VERSION_STRING >= WotLK
15864 // Dynamic aura 285 application, removing bonus
15866 {
15867 auto modifiableAurEff = aurEff->getAura()->getModifiableAuraEffect(aurEff->getEffectIndex());
15868 aurEff->getAura()->SpellAuraModAttackPowerOfArmor(modifiableAurEff, false);
15869 }
15870#endif
15871
15872 if (res < 0)
15873 res = 1;
15874
15875#if VERSION_STRING > Classic
15878#endif
15879 setResistance(type, res > 0 ? res : 0);
15880
15881 if (auto* const pet = getPet())
15882 pet->CalcResistance(type); //Re-calculate pet's too.
15883
15884#if VERSION_STRING >= WotLK
15885 // Dynamic aura 285 application, adding bonus
15887 {
15888 auto modifiableAurEff = aurEff->getAura()->getModifiableAuraEffect(aurEff->getEffectIndex());
15889 aurEff->getAura()->SpellAuraModAttackPowerOfArmor(modifiableAurEff, true);
15890 }
15891#endif
15892 }
15893}
15894
15896{
15897 if (type < 5)
15898 {
15899 int32_t pos = (int32_t)m_baseStats[type] * (int32_t)m_statModPctPos[type] / 100 + (int32_t)m_flatStatModPos[type];
15901 int32_t res = pos + (int32_t)m_baseStats[type] - neg;
15902 if (res <= 0)
15903 res = 1;
15904
15905 pos += (res * (int32_t)this->m_totalStatModPctPos[type]) / 100;
15906 neg += (res * (int32_t)this->m_totalStatModPctNeg[type]) / 100;
15907 res = pos + m_baseStats[type] - neg;
15908 if (res <= 0)
15909 res = 1;
15910
15911#if VERSION_STRING != Classic
15912 setPosStat(type, pos);
15913
15914 if (neg < 0)
15915 setNegStat(type, -neg);
15916 else
15917 setNegStat(type, neg);
15918#endif
15919
15920 setStat(type, res);
15921 if (type == STAT_AGILITY)
15922 calcResistance(0);
15923
15924 if (type == STAT_STAMINA || type == STAT_INTELLECT)
15925 {
15926 if (auto* const pet = getPet())
15927 pet->CalcStat(type); //Re-calculate pet's too
15928 }
15929 }
15930}
15931
15932void Player::regenerateHealth(bool inCombat)
15933{
15934 const auto currentHealth = getHealth();
15935 if (currentHealth == 0)
15936 return;
15937
15938 const auto maxHealth = getMaxHealth();
15939 if (currentHealth >= maxHealth)
15940 return;
15941
15942 float_t amt = 0.0f;
15943
15944 // While polymorphed health is regenerated rapidly
15945 // Exact value is yet unknown but it's roughly 10% of health per sec
15947 amt = getMaxHealth() * 0.10f;
15948 else
15949 amt = calculateHealthRegenerationValue(inCombat);
15950
15951 modHealth(static_cast<int32_t>(std::ceil(amt)));
15952}
15953
15954void Player::_Relocate(uint32_t mapid, const LocationVector& v, bool sendpending, bool force_new_world, uint32_t instance_id)
15955{
15956 // this func must only be called when switching between maps!
15957 if (sendpending && mapid != m_mapId && force_new_world)
15958 m_session->SendPacket(SmsgTransferPending(mapid).serialise().get());
15959
15960 bool sendpacket = (mapid == m_mapId);
15961 // Dismount before teleport and before being removed from world,
15962 // otherwise we may spawn the active pet while not being in world.
15963 dismount(false);
15964
15965 MySQLStructure::AreaTrigger const* areaTrigger = nullptr;
15966 bool check = false;
15967
15968 if (!sendpacket || force_new_world)
15969 {
15970 WorldMap* map = sMapMgr.createMap(mapid, this, instance_id);
15971 if (!map)
15972 {
15974 return;
15975 }
15976 else if (map->getBaseMap()->isInstanceMap())
15977 {
15978 if (auto state = map->cannotEnter(this))
15979 {
15980 switch (state)
15981 {
15984 break;
15986 m_session->systemMessage("Another group is already inside this instance of the dungeon.");
15987 break;
15990 break;
15992 m_session->SendPacket(SmsgTransferAborted(mapid, INSTANCE_ABORT_FULL).serialise().get());
15993 break;
15996 break;
15997 default:
15998 break;
15999 }
16000 areaTrigger = sMySQLStore.getMapGoBackTrigger(mapid);
16001 check = true;
16002 }
16003 else if (instance_id && !sInstanceMgr.getInstanceSave(instance_id)) // ... and instance is reseted then look for entrance.
16004 {
16005 areaTrigger = sMySQLStore.getMapEntranceTrigger(mapid);
16006 check = true;
16007 }
16008 }
16009
16010 // Special Cases
16011 if (check)
16012 {
16013 if (areaTrigger)
16014 {
16015 // our Instance got reset, port us to the entrance
16016 sendTeleportAckPacket(LocationVector(areaTrigger->x, areaTrigger->y, areaTrigger->z, areaTrigger->o));
16017 if (mapid != areaTrigger->mapId)
16018 {
16019 mapid = areaTrigger->mapId;
16020 map = sMapMgr.createMap(mapid, this);
16021 }
16022 }
16023 else
16024 {
16025 return;
16026 }
16027 }
16028
16029 if (IsInWorld())
16031
16032 m_session->SendPacket(SmsgNewWorld(mapid, v).serialise().get());
16033
16034 SetMapId(mapid);
16035 SetInstanceID(map->getInstanceId());
16036 }
16037 else
16038 {
16040 }
16041
16044 SetPosition(v);
16045
16046 if (sendpacket)
16048
16050
16051 m_zAxisPosition = 0.0f;
16052}
16053
16054#ifdef AE_TBC
16056{
16057 for (uint8_t slotIndex = 0; slotIndex < INVENTORY_KEYRING_END; ++slotIndex)
16058 {
16059 if (const auto inventoryItem = getItemInterface()->GetInventoryItem(slotIndex))
16060 {
16061 inventoryItem->PushToWorld(m_WorldMap);
16062
16063 if (slotIndex < INVENTORY_SLOT_BAG_END) // only equipment slots get mods.
16064 applyItemMods(inventoryItem, slotIndex, true, false, true);
16065
16066 if (slotIndex >= CURRENCYTOKEN_SLOT_START && slotIndex < CURRENCYTOKEN_SLOT_END)
16067 updateKnownCurrencies(inventoryItem->getEntry(), true);
16068
16069 if (inventoryItem->isContainer() && getItemInterface()->IsBagSlot(slotIndex))
16070 {
16071 for (uint32_t containerSlot = 0; containerSlot < inventoryItem->getItemProperties()->ContainerSlots; ++containerSlot)
16072 {
16073 if (Item* item = (static_cast<Container*>(inventoryItem))->getItem(static_cast<int16_t>(containerSlot)))
16074 item->PushToWorld(m_WorldMap);
16075 }
16076 }
16077 }
16078 }
16079
16080 updateStats();
16081}
16082#else
16084{
16085 for (uint8_t slotIndex = 0; slotIndex < CURRENCYTOKEN_SLOT_END; ++slotIndex)
16086 {
16087 if (Item* inventoryItem = getItemInterface()->GetInventoryItem(slotIndex))
16088 {
16089 inventoryItem->PushToWorld(m_WorldMap);
16090
16091 if (slotIndex < INVENTORY_SLOT_BAG_END)
16092 applyItemMods(inventoryItem, slotIndex, true, false, true);
16093
16094 if (slotIndex >= CURRENCYTOKEN_SLOT_START)
16095 updateKnownCurrencies(inventoryItem->getEntry(), true);
16096
16097 if (inventoryItem->isContainer() && getItemInterface()->IsBagSlot(slotIndex))
16098 {
16099 for (uint32_t containerSlot = 0; containerSlot < inventoryItem->getItemProperties()->ContainerSlots; ++containerSlot)
16100 {
16101 if (Item* item = (static_cast<Container*>(inventoryItem))->getItem(static_cast<int16_t>(containerSlot)))
16102 item->PushToWorld(m_WorldMap);
16103 }
16104 }
16105 }
16106 }
16107
16108 updateStats();
16109}
16110#endif
16111
16113{
16114 for (uint8_t slotIndex = 0; slotIndex < CURRENCYTOKEN_SLOT_END; ++slotIndex)
16115 {
16116 if (Item* inventoryItem = getItemInterface()->GetInventoryItem((int8_t)slotIndex))
16117 {
16118 if (inventoryItem->IsInWorld())
16119 {
16120 if (slotIndex < INVENTORY_SLOT_BAG_END)
16121 applyItemMods(inventoryItem, static_cast<int16_t>(slotIndex), false, false, true);
16122
16123 inventoryItem->removeFromWorld();
16124 }
16125
16126 if (inventoryItem->isContainer() && getItemInterface()->IsBagSlot(static_cast<int16_t>(slotIndex)))
16127 {
16128 for (uint32_t containerSlot = 0; containerSlot < inventoryItem->getItemProperties()->ContainerSlots; ++containerSlot)
16129 {
16130 Item* item = (static_cast<Container*>(inventoryItem))->getItem(static_cast<int16_t>(containerSlot));
16131 if (item && item->IsInWorld())
16132 item->removeFromWorld();
16133 }
16134 }
16135 }
16136 }
16137
16138 updateStats();
16139}
16140
16142{
16143 for (const auto& spellId : m_spellSet)
16144 {
16145 if (spellId == calledFrom)
16146 continue;
16147
16148 const auto spellSkillRange = sSpellMgr.getSkillEntryRangeForSpell(spellId);
16149 for (const auto& [_, skill_line_ability] : spellSkillRange)
16150 {
16151 if (skill_line_ability->skilline == skillLine)
16152 clearCooldownForSpell(spellId);
16153 }
16154 }
16155}
16156
16158{
16159 if (static_cast<int>(max) == -1)
16160 {
16161 if (static_cast<int>(current) != -1)
16162 sendStopMirrorTimerPacket(mirrorType);
16163
16164 return;
16165 }
16166
16167 getSession()->SendPacket(SmsgStartMirrorTimer(mirrorType, current, max, regen).serialise().get());
16168}
16169
16171{
16172 uint32_t level = getLevel();
16173 if (level > 100)
16174 level = 100;
16175
16176 uint32_t rating = getCombatRating(index);
16177
16178 WDB::Structures::GtCombatRatingsEntry const* combatRatingsEntry = sGtCombatRatingsStore.lookupEntry(index * 100 + level - 1);
16179 if (combatRatingsEntry == nullptr)
16180 return float(rating);
16181
16182 return (rating / combatRatingsEntry->val);
16183}
16184
16186{
16187 for (const auto& inRangeObject : getInRangeObjectsSet())
16188 {
16189 if (inRangeObject && inRangeObject->isPlayer())
16190 {
16191 auto group = static_cast<Player*>(inRangeObject)->getGroup();
16192 if (!group && group != getGroup())
16193 {
16194 BuildFieldUpdatePacket(static_cast<Player*>(inRangeObject), index, flag);
16195 }
16196 }
16197 }
16198}
16199
16201{
16203
16204 SpellCastTargets targets(getGuid());
16205
16206 if (getClass() == WARRIOR)
16207 castSpell(this, sSpellMgr.getSpellInfo(2457), true);
16208
16209 for (const auto& spellId : m_spellSet)
16210 {
16211 const auto spellInfo = sSpellMgr.getSpellInfo(spellId);
16212
16213 if (spellInfo != nullptr
16214 && (spellInfo->isPassive())
16215 && !(spellInfo->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET))
16216 {
16217 if (spellInfo->getRequiredShapeShift())
16218 {
16219 if (!(getShapeShiftMask() & spellInfo->getRequiredShapeShift()))
16220 continue;
16221 }
16222
16223 if (spellInfo->getCasterAuraState() != 0 && !hasAuraState(static_cast<AuraState>(spellInfo->getCasterAuraState()), spellInfo, this))
16224 continue;
16225
16226 Spell* newSpell = sSpellMgr.newSpell(this, spellInfo, true, nullptr);
16227 newSpell->prepare(&targets);
16228 }
16229 }
16230
16231 for (auto& loginaura : m_loginAuras)
16232 {
16233 if (SpellInfo const* sp = sSpellMgr.getSpellInfo(loginaura.id))
16234 {
16235 if (sp->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)
16236 continue; //do not load auras that only exist while pet exist. We should recast these when pet is created anyway
16237
16238 auto aura = sSpellMgr.newAura(sp, loginaura.dur, this, this, false);
16239 for (uint8_t x = 0; x < 3; x++)
16240 {
16241 if (sp->getEffect(x) == SPELL_EFFECT_APPLY_AURA)
16242 {
16243 aura->addAuraEffect(static_cast<AuraEffect>(sp->getEffectApplyAuraName(x)), sp->getEffectBasePoints(x) + 1, sp->getEffectMiscValue(x), 1.0f, false, x);
16244 }
16245 }
16246
16247 if (sp->getProcCharges() > 0 && loginaura.charges > 0)
16248 aura->setCharges(static_cast<uint16_t>(loginaura.charges), false);
16249
16250 this->addAura(std::move(aura));
16251 }
16252 }
16253
16255 {
16257 }
16259 {
16260 if (const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow()))
16262 else
16264 }
16265
16266 if (isDead())
16267 {
16268 if (getCorpseInstanceId() != 0)
16269 {
16270 if (const auto corpse = sObjectMgr.getCorpseByOwner(getGuidLow()))
16271 corpse->resetDeathClock();
16272
16274 }
16275 }
16276
16277#if VERSION_STRING > TBC
16278 // useless logon spell
16279 Spell* logonspell = sSpellMgr.newSpell(this, sSpellMgr.getSpellInfo(836), false, nullptr);
16280 logonspell->prepare(&targets);
16281#endif
16282
16283 if (isBanned())
16284 {
16285 kickFromServer(10000);
16288 }
16289
16290 if (m_playerInfo->m_Group)
16291 {
16293 }
16294
16296 {
16297 sendRaidGroupOnly(0xFFFFFFFF, 0);
16298 m_sendOnlyRaidgroup = false;
16299 }
16300
16301#if VERSION_STRING > TBC
16302 // add glyphs
16303 for (uint8_t j = 0; j < GLYPHS_COUNT; ++j)
16304 {
16305 auto glyph_properties = sGlyphPropertiesStore.lookupEntry(m_specs[m_talentActiveSpec].getGlyph(j));
16306 if (glyph_properties == nullptr)
16307 continue;
16308
16309 castSpell(this, glyph_properties->SpellID, true);
16310 }
16311
16312 //sEventMgr.AddEvent(this,&Player::SendAllAchievementData,EVENT_SEND_ACHIEVEMNTS_TO_PLAYER,ACHIEVEMENT_SEND_DELAY,1,0);
16314#endif
16315}
16316
16317void Player::modifyBonuses(uint32_t type, int32_t val, bool apply)
16318{
16319 // Added some updateXXXX calls so when an item modifies a stat they get updated
16320 // also since this is used by auras now it will handle it for those
16321 int32_t _val = val;
16322 if (!apply)
16323 val = -val;
16324
16325 switch (type)
16326 {
16327 case ITEM_MOD_MANA:
16328 {
16330 m_manaFromItems += val;
16331 }
16332 break;
16333 case ITEM_MOD_HEALTH:
16334 {
16335 modMaxHealth(val);
16336 m_healthFromItems += val;
16337 }
16338 break;
16339 case ITEM_MOD_AGILITY: // modify agility
16340 case ITEM_MOD_STRENGTH: // modify strength
16341 case ITEM_MOD_INTELLECT: // modify intellect
16342 case ITEM_MOD_SPIRIT: // modify spirit
16343 case ITEM_MOD_STAMINA: // modify stamina
16344 {
16345 uint8_t convert[] = { 1, 0, 3, 4, 2 };
16346 if (_val > 0)
16347 m_flatStatModPos[convert[type - 3]] += val;
16348 else
16349 m_flatStatModNeg[convert[type - 3]] -= val;
16350 calcStat(convert[type - 3]);
16351 }
16352 break;
16354 {
16356 modCombatRating(CR_WEAPON_SKILL_MAINHAND, val); // melee main hand
16357 modCombatRating(CR_WEAPON_SKILL_OFFHAND, val); // melee off hand
16358 }
16359 break;
16361 {
16363 }
16364 break;
16366 {
16368 }
16369 break;
16371 {
16373 }
16374 break;
16376 {
16378 }
16379 break;
16381 {
16383 }
16384 break;
16386 {
16388 }
16389 break;
16391 {
16393 }
16394 break;
16396 {
16398 }
16399 break;
16401 {
16403 }
16404 break;
16406 {
16408 }
16409 break;
16411 {
16413 }
16414 break;
16416 {
16418 }
16419 break;
16421 {
16423 }
16424 break;
16426 {
16427
16428 } break;
16430 {
16431
16432 } break;
16434 {
16435
16436 } break;
16438 {
16439 modCombatRating(CR_HASTE_MELEE, val); // melee
16440 }
16441 break;
16443 {
16444 modCombatRating(CR_HASTE_RANGED, val); // ranged
16445 }
16446 break;
16448 {
16449 modCombatRating(CR_HASTE_SPELL, val); // spell
16450 }
16451 break;
16453 {
16454 modCombatRating(CR_HIT_MELEE, val); // melee
16455 modCombatRating(CR_HIT_RANGED, val); // ranged
16456 modCombatRating(CR_HIT_SPELL, val); // spell
16457 }
16458 break;
16460 {
16461 modCombatRating(CR_CRIT_MELEE, val); // melee
16462 modCombatRating(CR_CRIT_RANGED, val); // ranged
16463 modCombatRating(CR_CRIT_SPELL, val); // spell
16464 }
16465 break;
16466 case ITEM_MOD_HIT_AVOIDANCE_RATING: // this is guessed based on layout of other fields
16467 {
16468 modCombatRating(CR_HIT_TAKEN_MELEE, val); // melee
16469 modCombatRating(CR_HIT_TAKEN_RANGED, val); // ranged
16470 modCombatRating(CR_HIT_TAKEN_SPELL, val); // spell
16471 }
16472 break;
16474 {
16475
16476 } break;
16478 {
16480 }
16481 break;
16483 {
16484#if VERSION_STRING >= Cata
16487#else
16488 modCombatRating(CR_CRIT_TAKEN_MELEE, val); // melee
16489 modCombatRating(CR_CRIT_TAKEN_RANGED, val); // ranged
16490#endif
16491 modCombatRating(CR_CRIT_TAKEN_SPELL, val); // spell
16492 }
16493 break;
16495 {
16496 modCombatRating(CR_HASTE_MELEE, val); // melee
16497 modCombatRating(CR_HASTE_RANGED, val); // ranged
16498 modCombatRating(CR_HASTE_SPELL, val); // spell
16499 }
16500 break;
16502 {
16503 modAttackPowerMods(val);
16505 }
16506 break;
16508 {
16510 }
16511 break;
16513 {
16514 modAttackPowerMods(val);
16515 }
16516 break;
16517#if VERSION_STRING > Classic
16519 {
16520 for (uint8_t school = 1; school < TOTAL_SPELL_SCHOOLS; ++school)
16521 {
16522 m_healDoneMod[school] += val;
16523 }
16524 modModHealingDone(val);
16525 }
16526 break;
16527#endif
16529 {
16530 for (uint8_t school = 1; school < TOTAL_SPELL_SCHOOLS; ++school)
16531 {
16532 modModDamageDonePositive(school, val);
16533 }
16534 }
16535 break;
16537 {
16538 m_manaFromItems += val;
16539 }
16540 break;
16541#if VERSION_STRING >= WotLK
16543 {
16545 }
16546 break;
16547#endif
16549 {
16550 for (uint8_t school = 1; school < 7; ++school)
16551 {
16552 modModDamageDonePositive(school, val);
16553 m_healDoneMod[school] += val;
16554 }
16555#if VERSION_STRING > Classic
16556 modModHealingDone(val);
16557#endif
16558 }
16559 break;
16560 }
16561}
16562
16563void Player::saveAuras(std::stringstream& ss)
16564{
16565 ss << "'";
16566 uint32_t charges = 0;
16567 uint16_t prevX = 0;
16568
16569 // save all auras why only just positive?
16571 {
16572 auto* const aur = getAuraWithAuraSlot(x);
16573 if (aur != nullptr && aur->getTimeLeft() > 3000)
16574 {
16575 for (uint8_t i = 0; i < 3; ++i)
16576 if (aur->getSpellInfo()->getEffect(i) == SPELL_EFFECT_APPLY_GROUP_AREA_AURA || aur->getSpellInfo()->getEffect(i) == SPELL_EFFECT_APPLY_RAID_AREA_AURA || aur->getSpellInfo()->getEffect(i) == SPELL_EFFECT_ADD_FARSIGHT)
16577 continue;
16578
16579 if (aur->pSpellId)
16580 continue; // these auras were gained due to some proc. We do not save these either to avoid exploits of not removing them
16581
16582 if (aur->getSpellInfo()->custom_c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)
16583 continue;
16584
16585 // we are going to cast passive spells anyway on login so no need to save auras for them
16586 if (aur->IsPassive() && !(aur->getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NO_INITIAL_AGGRO))
16587 continue;
16588
16589 auto* const prevAura = getAuraWithAuraSlot(prevX);
16590 if (charges > 0 && aur->getSpellId() != prevAura->getSpellId())
16591 {
16592 ss << prevAura->getSpellId() << "," << prevAura->getTimeLeft() << "," << !prevAura->isNegative() << "," << charges << ",";
16593 charges = 0;
16594 }
16595
16596 if (aur->getSpellInfo()->getProcCharges() == 0)
16597 ss << aur->getSpellId() << "," << aur->getTimeLeft() << "," << !aur->isNegative() << "," << uint32_t(0) << ",";
16598 else
16599 charges++;
16600
16601 prevX = x;
16602 }
16603 }
16604
16605 auto* const prevAura = getAuraWithAuraSlot(prevX);
16606 if (charges > 0 && prevAura)
16607 ss << prevAura->getSpellId() << "," << prevAura->getTimeLeft() << "," << !prevAura->isNegative() << "," << charges << ",";
16608
16609 ss << "'";
16610}
16611
16613{
16614 float rangeDamage;
16615
16616 // Mainhand
16617 float attackPowerBonus = getCalculatedAttackPower() / 14000.0f;
16619
16620 if (isInFeralForm())
16621 {
16622 float damageMod = 1;
16623 for (std::map<uint32_t, WeaponModifier>::iterator i = m_damageDone.begin(); i != m_damageDone.end(); ++i)
16624 {
16625 if (i->second.wclass == (uint32_t)-1) // applying only "any weapon" modifiers
16626 damageMod += i->second.value;
16627 }
16628
16629 uint32_t level = getLevel();
16630 float averageFeralDamage;
16631 uint32_t itemLeven; // the two hand weapon with dps equal to cat or bear dps
16632
16633 uint8_t shapeShiftForm = getShapeShiftForm();
16634 if (shapeShiftForm == FORM_CAT)
16635 {
16636 if (level < 42)
16637 itemLeven = level - 1;
16638 else if (level < 46)
16639 itemLeven = level;
16640 else if (level < 49)
16641 itemLeven = 2 * level - 45;
16642 else if (level < 60)
16643 itemLeven = level + 4;
16644 else
16645 itemLeven = 64;
16646
16647 // 3rd grade polinom for calculating blue two-handed weapon dps based on itemlevel
16648 if (itemLeven <= 28)
16649 averageFeralDamage = 1.563e-03f * itemLeven * itemLeven * itemLeven - 1.219e-01f * itemLeven * itemLeven + 3.802e+00f * itemLeven - 2.227e+01f;
16650 else if (itemLeven <= 41)
16651 averageFeralDamage = -3.817e-03f * itemLeven * itemLeven * itemLeven + 4.015e-01f * itemLeven * itemLeven - 1.289e+01f * itemLeven + 1.530e+02f;
16652 else
16653 averageFeralDamage = 1.829e-04f * itemLeven * itemLeven * itemLeven - 2.692e-02f * itemLeven * itemLeven + 2.086e+00f * itemLeven - 1.645e+01f;
16654
16655 rangeDamage = averageFeralDamage * 0.79f + deltaDone + attackPowerBonus * 1000.0f;
16656 rangeDamage *= damageMod;
16657 setMinDamage(rangeDamage > 0 ? rangeDamage : 0);
16658
16659 rangeDamage = averageFeralDamage * 1.21f + deltaDone + attackPowerBonus * 1000.0f;
16660 rangeDamage *= damageMod;
16661 setMaxDamage(rangeDamage > 0 ? rangeDamage : 0);
16662 }
16663 else // Bear or Dire Bear Form
16664 {
16665 if (shapeShiftForm == FORM_BEAR)
16666 itemLeven = level;
16667 else
16668 itemLeven = level + 5; // DIRE_BEAR dps is slightly better than bear dps
16669
16670 if (itemLeven > 70)
16671 itemLeven = 70;
16672
16673 // 3rd grade polinom for calculating green two-handed weapon dps based on itemlevel
16674 if (itemLeven <= 30)
16675 averageFeralDamage = 7.638e-05f * itemLeven * itemLeven * itemLeven + 1.874e-03f * itemLeven * itemLeven + 4.967e-01f * itemLeven + 1.906e+00f;
16676 else if (itemLeven <= 44)
16677 averageFeralDamage = -1.412e-03f * itemLeven * itemLeven * itemLeven + 1.870e-01f * itemLeven * itemLeven - 7.046e+00f * itemLeven + 1.018e+02f;
16678 else
16679 averageFeralDamage = 2.268e-04f * itemLeven * itemLeven * itemLeven - 3.704e-02f * itemLeven * itemLeven + 2.784e+00f * itemLeven - 3.616e+01f;
16680
16681 averageFeralDamage *= 2.5f; // Bear Form attack speed
16682
16683 rangeDamage = averageFeralDamage * 0.79f + deltaDone + attackPowerBonus * 2500.0f;
16684 rangeDamage *= damageMod;
16685 setMinDamage(rangeDamage > 0 ? rangeDamage : 0);
16686
16687 rangeDamage = averageFeralDamage * 1.21f + deltaDone + attackPowerBonus * 2500.0f;
16688 rangeDamage *= damageMod;
16689 setMaxDamage(rangeDamage > 0 ? rangeDamage : 0);
16690 }
16691
16692 return;
16693 }
16694
16695 // no druid shapeShift
16696 uint32_t speed = 2000;
16698
16699 if (item && !m_isDisarmed)
16700 speed = item->getItemProperties()->Delay;
16701
16702 float bonus = attackPowerBonus * speed;
16703 float damageMod = 1;
16704 for (std::map<uint32_t, WeaponModifier>::iterator weaponMod = m_damageDone.begin(); weaponMod != m_damageDone.end(); ++weaponMod)
16705 {
16706 if ((weaponMod->second.wclass == (uint32_t)-1) || //any weapon
16707 (item && ((1 << item->getItemProperties()->SubClass) & weaponMod->second.subclass)))
16708 damageMod += weaponMod->second.value;
16709 }
16710
16711 rangeDamage = m_baseDamage[0] + deltaDone + bonus;
16712 rangeDamage *= damageMod;
16713 setMinDamage(rangeDamage > 0 ? rangeDamage : 0);
16714
16715 rangeDamage = m_baseDamage[1] + deltaDone + bonus;
16716 rangeDamage *= damageMod;
16717 setMaxDamage(rangeDamage > 0 ? rangeDamage : 0);
16718
16719 uint32_t cr = 0;
16720 if (item)
16721 {
16722 if (this->m_wratings.size())
16723 {
16724 std::map<uint32_t, uint32_t>::iterator itr = m_wratings.find(item->getItemProperties()->SubClass);
16725 if (itr != m_wratings.end())
16726 cr = itr->second;
16727 }
16728 }
16729 //\todo investigate
16730#if VERSION_STRING != Classic
16732#endif
16733 // Mainhand END
16734
16735 // Offhand START
16736 cr = 0;
16738 if (item)
16739 {
16740 if (!m_isDisarmed)
16741 speed = item->getItemProperties()->Delay;
16742 else
16743 speed = 2000;
16744
16745 bonus = attackPowerBonus * speed;
16746
16747 damageMod = 1;
16748 for (std::map<uint32_t, WeaponModifier>::iterator i = m_damageDone.begin(); i != m_damageDone.end(); ++i)
16749 {
16750 if ((i->second.wclass == (uint32_t)-1) || //any weapon
16751 (((1 << item->getItemProperties()->SubClass) & i->second.subclass))
16752 )
16753 damageMod += i->second.value;
16754 }
16755
16756 rangeDamage = (m_baseOffhandDamage[0] + deltaDone + bonus) * m_offhandDmgMod;
16757 rangeDamage *= damageMod;
16758 setMinOffhandDamage(rangeDamage > 0 ? rangeDamage : 0);
16759
16760 rangeDamage = (m_baseOffhandDamage[1] + deltaDone + bonus) * m_offhandDmgMod;
16761 rangeDamage *= damageMod;
16762 setMaxOffhandDamage(rangeDamage > 0 ? rangeDamage : 0);
16763
16764 if (m_wratings.size())
16765 {
16766 std::map<uint32_t, uint32_t>::iterator itr = m_wratings.find(item->getItemProperties()->SubClass);
16767 if (itr != m_wratings.end())
16768 cr = itr->second;
16769 }
16770 }
16771 //\todo investigate
16772#if VERSION_STRING != Classic
16774#endif
16775 // Offhand END
16776 // Ranged
16777 cr = 0;
16779 if (item)
16780 {
16781 damageMod = 1;
16782 for (std::map<uint32_t, WeaponModifier>::iterator weaponMod = m_damageDone.begin(); weaponMod != m_damageDone.end(); ++weaponMod)
16783 {
16784 if ((weaponMod->second.wclass == (uint32_t)-1) || //any weapon
16785 (((1 << item->getItemProperties()->SubClass) & weaponMod->second.subclass)))
16786 {
16787 damageMod += weaponMod->second.value;
16788 }
16789 }
16790
16791#if VERSION_STRING < Cata
16792 if (item->getItemProperties()->SubClass != 19)//wands do not have bonuses from RAP & ammo
16793 {
16794 // ap_bonus = (getRangedAttackPower()+(int32_t)getRangedAttackPowerMods())/14000.0;
16795 attackPowerBonus = getCalculatedRangedAttackPower() / 14000.0f;
16796 bonus = attackPowerBonus * item->getItemProperties()->Delay;
16797
16798 if (getAmmoId() && !m_requiresNoAmmo)
16799 {
16800 ItemProperties const* xproto = sMySQLStore.getItemProperties(getAmmoId());
16801 if (xproto)
16802 {
16803 bonus += ((xproto->Damage[0].Min + xproto->Damage[0].Max) * item->getItemProperties()->Delay) / 2000.0f;
16804 }
16805 }
16806 }
16807 else
16808#endif
16809 bonus = 0;
16810
16811 rangeDamage = m_baseRangedDamage[0] + deltaDone + bonus;
16812 rangeDamage *= damageMod;
16813 setMinRangedDamage(rangeDamage > 0 ? rangeDamage : 0);
16814
16815 rangeDamage = m_baseRangedDamage[1] + deltaDone + bonus;
16816 rangeDamage *= damageMod;
16817 setMaxRangedDamage(rangeDamage > 0 ? rangeDamage : 0);
16818
16819 if (m_wratings.size())
16820 {
16821 std::map<uint32_t, uint32_t>::iterator itr = m_wratings.find(item->getItemProperties()->SubClass);
16822 if (itr != m_wratings.end())
16823 cr = itr->second;
16824 }
16825
16826 }
16827 //\todo investigate
16828#if VERSION_STRING != Classic
16830#endif
16831 // Ranged END
16832 if (auto* const pet = getPet())
16833 pet->calculateDamage();//Re-calculate pet's too
16834}
16835
16837{
16838 float result;
16839
16840 float attackPowerBonus;
16841 if (attackPowerOverride)
16842 attackPowerBonus = attackPowerOverride / 14000.0f;
16843 else
16844 attackPowerBonus = getCalculatedAttackPower() / 14000.0f;
16845
16846 if (isInFeralForm())
16847 {
16848 if (getShapeShiftForm() == FORM_CAT)
16849 result = attackPowerBonus * 1000.0f;
16850 else
16851 result = attackPowerBonus * 2500.0f;
16852
16853 return Util::float2int32(result);
16854 }
16855
16856 // no druid shapeShift
16857 uint32_t speed = 2000;
16859 if (item && !m_isDisarmed)
16860 speed = item->getItemProperties()->Delay;
16861
16862 result = attackPowerBonus * speed;
16863 return Util::float2int32(result);
16864}
16865
16866#if VERSION_STRING > TBC
16867void Player::updateAchievementCriteria(AchievementCriteriaTypes type, int32_t miscValue1 /*= 0*/, int32_t miscValue2 /*= 0*/, uint32_t miscValue3 /*= 0*/, Unit* unit /*= nullptr*/)
16868{
16869 m_achievementMgr->updateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit);
16870 Guild* guild = sGuildMgr.getGuildById(getGuildId());
16871 if (!guild)
16872 return;
16873
16874 // Update only individual achievement criteria here, otherwise we may get multiple updates
16875 // from a single boss kill
16876 if (m_achievementMgr->isGroupCriteriaType(type))
16877 return;
16878
16879 // ToDo Cata Has Guild Achievements
16880 //guild->updateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
16881}
16882#endif
16883
16885{
16886 // unit checks
16887 if (!guid)
16888 return nullptr;
16889
16890 if (!IsInWorld())
16891 return nullptr;
16892
16893 if (isInFlight())
16894 return nullptr;
16895
16896 Creature* creature = getWorldMapCreature(guid.getRawGuid());
16897 if (!creature)
16898 return nullptr;
16899
16900 // Deathstate checks
16901 if (!isAlive() && !(creature->GetCreatureProperties()->typeFlags & CREATURE_FLAG1_GHOST))
16902 return nullptr;
16903
16904 // alive or spirit healer
16905 if (!creature->isAlive() && !(creature->GetCreatureProperties()->typeFlags & CREATURE_FLAG1S_DEAD_INTERACT))
16906 return nullptr;
16907
16908 // appropriate npc type
16909 if (npcflagmask && !(creature->getNpcFlags() & npcflagmask))
16910 return nullptr;
16911
16912 // not allow interaction under control, but allow with own pets
16913 if (creature->getCharmGuid())
16914 return nullptr;
16915
16916 // not unfriendly/hostile
16917 if (this->isHostileTo(creature))
16918 return nullptr;
16919
16920 // not too far
16921 if (!creature->IsWithinDistInMap(this, creature->getCombatReach() + 4.0f))
16922 return nullptr;
16923
16924 return creature;
16925}
@ EVENT_FOLLOWOWNER
Definition AIEvents.h:22
AuraEffect
@ SPELL_AURA_PREVENT_RESURRECTION
@ SPELL_AURA_RETAIN_COMBO_POINTS
@ SPELL_AURA_MOD_ALL_WEAPON_SKILLS
@ SPELL_AURA_MOD_RANGED_ATTACK_POWER_BY_STAT_PCT
@ SPELL_AURA_PERIODIC_POWER_PCT
@ SPELL_AURA_MOD_SKILL
@ SPELL_AURA_MOD_SHAPESHIFT
@ SPELL_AURA_PERIODIC_HEAL_PCT
@ SPELL_AURA_MOD_POWER_REGEN
@ SPELL_AURA_EXPERTISE
@ SPELL_AURA_ALLOW_TAME_PET_TYPE
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_ATTACK_POWER_BY_STAT_PCT
@ SPELL_AURA_MOD_HEALTH_REGEN
@ SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
@ SPELL_AURA_MOD_STEALTH
@ SPELL_AURA_NONE
@ SPELL_AURA_MOD_SKILL_TALENT
@ AURA_INTERRUPT_ON_ENTER_WATER
@ AURA_INTERRUPT_ON_MOVEMENT
@ AURA_INTERRUPT_ON_STAND_UP
@ AURA_INTERRUPT_ON_LEAVE_AREA
@ AURA_INTERRUPT_ON_TURNING
@ AURA_INTERRUPT_ON_LEAVE_WATER
AuraState
Definition AuraStates.hpp:9
std::vector< AsyncQueryResult > QueryResultVector
Definition CallBack.h:223
#define sChannelMgr
@ E_CHAR_LOGIN_NO_CHARACTER
@ CHAT_MSG_SYSTEM
#define MSG_COLOR_YELLOW
@ LANG_UNIVERSAL
#define MSG_COLOR_GREEN
#define M_PI_FLOAT
#define M_PI
#define CORPSE_RECLAIM_TIME_MS
@ CORPSE_STATE_BODY
Definition Corpse.hpp:15
@ CORPSE_FLAG_UNK1
Definition Corpse.hpp:24
@ CORPSE_FLAG_LOOT
Definition Corpse.hpp:27
@ CORPSE_FLAG_HIDDEN_CLOAK
Definition Corpse.hpp:26
@ CORPSE_FLAG_HIDDEN_HELM
Definition Corpse.hpp:25
@ CREATURE_FLAG1S_DEAD_INTERACT
@ CREATURE_FLAG1_GHOST
@ RESTRICTION_CHECK_ALL
@ RESTRICTION_CHECK_MOUNT_VENDOR
this checks for all possible values in table
#define CharacterDatabase
@ EVENT_PLAYER_DUEL_COUNTDOWN
Definition EventMgr.h:57
@ EVENT_PLAYER_FORCED_RESURRECT
Zack 2007 05 28: similar to pet expire but we can have multiple guardians.
Definition EventMgr.h:64
@ EVENT_PLAYER_EJECT_FROM_INSTANCE
Definition EventMgr.h:76
@ EVENT_PLAYER_CHECKFORCHEATS
Definition EventMgr.h:44
@ EVENT_PLAYER_TELEPORT
Definition EventMgr.h:59
@ EVENT_PLAYER_SOFT_DISCONNECT
Zack 2007 06 08: After player not pushing release spirit for 6 minutes while dead.
Definition EventMgr.h:65
@ EVENT_PLAYER_UPDATE
Definition EventMgr.h:33
@ EVENT_PLAYER_CHARM_ATTACK
Definition EventMgr.h:52
@ EVENT_SEND_PACKET_TO_PLAYER_AFTER_LOGIN
Definition EventMgr.h:87
@ EVENT_PLAYER_DUEL_BOUNDARY_CHECK
Definition EventMgr.h:58
@ EVENT_CANNIBALIZE
Definition EventMgr.h:48
@ EVENT_PLAYER_KICK
Definition EventMgr.h:53
@ EVENT_UNK
Definition EventMgr.h:30
@ EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT
Definition EventMgr.h:109
#define sEventMgr
Definition EventMgr.h:278
@ GO_ACTIVATED
@ GAMEOBJECT_TYPE_CHEST
@ MEMBER_STATUS_AFK
Definition Group.h:91
@ MEMBER_STATUS_PVP
Definition Group.h:86
@ MEMBER_STATUS_ONLINE
Definition Group.h:85
@ MEMBER_STATUS_DEAD
Definition Group.h:87
@ MEMBER_STATUS_GHOST
Definition Group.h:88
@ MEMBER_STATUS_DND
Definition Group.h:92
@ MEMBER_STATUS_PVP_FFA
Definition Group.h:89
@ GROUP_UPDATE_FULL
Definition Group.h:75
@ GROUP_UPDATE_FLAG_STATUS
Definition Group.h:54
@ GROUP_UPDATE_FLAG_NONE
Definition Group.h:53
#define GUILD_RANK_NONE
#define sGuildMgr
Definition GuildMgr.hpp:63
#define sHookInterface
@ INSTANCE_RESET_CHANGE_DIFFICULTY
@ INSTANCE_RESET_ALL
@ CANNOT_ENTER_MAX_PLAYERS
@ CANNOT_ENTER_TOO_MANY_INSTANCES
@ CANNOT_ENTER_ENCOUNTER
@ CANNOT_ENTER_INSTANCE_BIND_MISMATCH
@ CANNOT_ENTER_DIFFICULTY_UNAVAILABLE
@ RAID_INSTANCE_WARNING_MIN
@ RAID_INSTANCE_WARNING_MIN_SOON
@ RAID_INSTANCE_WARNING_HOURS
@ RAID_INSTANCE_WELCOME
@ INSTANCE_ABORT_FULL
@ INSTANCE_ABORT_ENCOUNTER
@ INSTANCE_ABORT_HEROIC_MODE_NOT_AVAILABLE
@ INSTANCE_ABORT_TOO_MANY
@ INSTANCE_ABORT_NOT_FOUND
BindExtensionState
@ EXTEND_STATE_NORMAL
@ EXTEND_STATE_EXTENDED
@ EXTEND_STATE_EXPIRED
@ EXTEND_STATE_KEEP
#define sInstanceMgr
@ USE
@ CHANCE_ON_HIT
@ ON_EQUIP
@ ITEM_FLAG_UNIQUE_EQUIP
@ ITEM_CLASS_QUIVER
@ ITEM_CLASS_CONTAINER
@ ITEM_CLASS_ARMOR
@ ITEM_CLASS_WEAPON
@ INVENTORY_SLOT_ITEM_START
@ INVENTORY_SLOT_ITEM_END
@ EQUIPMENT_SLOT_MAINHAND
@ EQUIPMENT_SLOT_END
@ EQUIPMENT_SLOT_OFFHAND
@ EQUIPMENT_SLOT_START
@ EQUIPMENT_SLOT_RANGED
ItemModType
@ ITEM_MOD_HOLY_RESISTANCE
@ ITEM_MOD_HIT_AVOIDANCE_RATING
@ ITEM_MOD_MELEE_CRITICAL_AVOIDANCE_RATING
@ ITEM_MOD_NATURE_RESISTANCE
@ ITEM_MOD_SPELL_CRITICAL_AVOIDANCE_RATING
@ ITEM_MOD_STAMINA
@ ITEM_MOD_SPELL_PENETRATION
@ ITEM_MOD_PARRY_RATING
@ ITEM_MOD_MELEE_HIT_RATING
@ ITEM_MOD_MELEE_HASTE_RATING
@ ITEM_MOD_RANGED_CRITICAL_STRIKE_RATING
@ ITEM_MOD_EXPERTISE_RATING
@ ITEM_MOD_MANA
@ ITEM_MOD_SPELL_HIT_AVOIDANCE_RATING
@ ITEM_MOD_RANGED_ATTACK_POWER
@ ITEM_MOD_HEALTH
@ ITEM_MOD_CRITICAL_STRIKE_RATING
@ ITEM_MOD_RANGED_HASTE_RATING
@ ITEM_MOD_CRITICAL_AVOIDANCE_RATING
@ ITEM_MOD_RANGED_HIT_AVOIDANCE_RATING
@ ITEM_MOD_SPIRIT
@ ITEM_MOD_FROST_RESISTANCE
@ ITEM_MOD_SPELL_POWER
@ ITEM_MOD_SHADOW_RESISTANCE
@ ITEM_MOD_ATTACK_POWER
@ ITEM_MOD_MELEE_HIT_AVOIDANCE_RATING
@ ITEM_MOD_FIRE_RESISTANCE
@ ITEM_MOD_HASTE_RATING
@ ITEM_MOD_SPELL_CRITICAL_STRIKE_RATING
@ ITEM_MOD_BLOCK_VALUE
@ ITEM_MOD_SHIELD_BLOCK_RATING
@ ITEM_MOD_SPELL_HASTE_RATING
@ ITEM_MOD_RANGED_HIT_RATING
@ ITEM_MOD_STRENGTH
@ ITEM_MOD_HEALTH_REGEN
@ ITEM_MOD_FERAL_ATTACK_POWER
@ ITEM_MOD_ARMOR_PENETRATION_RATING
@ ITEM_MOD_SPELL_HEALING_DONE
@ ITEM_MOD_WEAPON_SKILL_RATING
@ ITEM_MOD_DEFENSE_RATING
@ ITEM_MOD_ARCANE_RESISTANCE
@ ITEM_MOD_SPELL_HIT_RATING
@ ITEM_MOD_MANA_REGENERATION
@ ITEM_MOD_HIT_RATING
@ ITEM_MOD_INTELLECT
@ ITEM_MOD_RESILIENCE_RATING
@ ITEM_MOD_AGILITY
@ ITEM_MOD_DODGE_RATING
@ ITEM_MOD_MELEE_CRITICAL_STRIKE_RATING
@ ITEM_MOD_RANGED_CRITICAL_AVOIDANCE_RATING
@ ITEM_MOD_SPELL_DAMAGE_DONE
@ ADD_ITEM_RESULT_OK
#define VOID_STORAGE_MAX_SLOT
@ INVENTORY_SLOT_BAG_START
@ INVENTORY_SLOT_BAG_END
@ VOID_TRANSFER_ERROR_FULL
@ VOID_TRANSFER_ERROR_INTERNAL_ERROR_1
@ INV_ERR_BAG_FULL
@ INV_ERR_ALREADY_LOOTED
@ INV_ERR_INVENTORY_FULL
@ INVTYPE_RANGED
@ INVTYPE_THROWN
@ INVTYPE_RANGEDRIGHT
@ INVTYPE_2HWEAPON
@ INVTYPE_SHIELD
EnchantmentSlot
@ PERM_ENCHANTMENT_SLOT
@ TEMP_ENCHANTMENT_SLOT
@ MAX_INSPECTED_ENCHANTMENT_SLOT
@ SOCK_ENCHANTMENT_SLOT1
@ REFORGE_ENCHANTMENT_SLOT
#define INVENTORY_SLOT_NOT_SET
#define INVENTORY_KEYRING_END
#define CURRENCYTOKEN_SLOT_START
#define CURRENCYTOKEN_SLOT_END
#define MAX_ITEM_PROTO_DAMAGES
Definition ItemMacros.hpp:9
#define MAX_ITEM_PROTO_SPELLS
#define MAX_ITEM_PROTO_STATS
#define sLogger
Definition Logger.hpp:136
#define sLogonCommHandler
@ REALMTYPE_NORMAL
@ REALMTYPE_PVP
@ REALMTYPE_RPPVP
@ REALMTYPE_RP
@ LOOT_SLOT_TYPE_MASTER
@ LOOT_SLOT_TYPE_ROLL_ONGOING
@ LOOT_SLOT_TYPE_ALLOW_LOOT
std::set< uint32_t > LooterSet
PartyLootMethod
@ PARTY_LOOT_MASTER_LOOTER
@ PARTY_LOOT_ROUND_ROBIN
@ PARTY_LOOT_NEED_BEFORE_GREED
@ PARTY_LOOT_GROUP
@ PARTY_LOOT_FREE_FOR_ALL
#define sLootMgr
Definition LootMgr.hpp:106
std::map< uint32_t, std::unique_ptr< PersonaltemList > > PersonaltemMap
Definition Loot.hpp:32
@ MAIL_TYPE_NORMAL
Definition MailMgr.h:56
@ MAIL_STATIONERY_GM
Definition MailMgr.h:88
#define sMailSystem
Definition MailMgr.h:189
#define sMapMgr
Definition MapMgr.hpp:91
#define IS_INSTANCE(a)
@ MOVEFLAG_TURNING_MASK
@ MOVEFLAG_MOTION_MASK
@ MOVEFLAG_MOVE_STOP
@ MOVEFLAG_FALLING
@ MOVEFLAG_NONE
@ MOVEFLAG_SWIMMING
#define sMySQLStore
@ WMI_INSTANCE_XPACK_01
@ WMI_INSTANCE_XPACK_02
@ TYPEID_UNIT
@ TYPEID_PLAYER
@ TYPE_PLAYER
@ GO_STATE_CLOSED
#define sObjectMgr
CurrentSpellType
Definition Object.hpp:65
@ CURRENT_CHANNELED_SPELL
Definition Object.hpp:68
@ CURRENT_GENERIC_SPELL
Definition Object.hpp:67
@ CURRENT_SPELL_MAX
Definition Object.hpp:70
@ CURRENT_AUTOREPEAT_SPELL
Definition Object.hpp:69
@ SMSG_LOAD_EQUIPMENT_SET
Definition Opcodes.hpp:1770
@ SMSG_FORCE_TURN_RATE_CHANGE
Definition Opcodes.hpp:802
@ MSG_MOVE_SET_SWIM_BACK_SPEED
Definition Opcodes.hpp:255
@ SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED
Definition Opcodes.hpp:1772
@ MSG_MOVE_SET_TURN_RATE
Definition Opcodes.hpp:259
@ SMSG_FORCE_WALK_SPEED_CHANGE
Definition Opcodes.hpp:798
@ SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
Definition Opcodes.hpp:981
@ SMSG_PET_TAME_FAILURE
Definition Opcodes.hpp:416
@ SMSG_RAID_INSTANCE_MESSAGE
Definition Opcodes.hpp:832
@ MSG_MOVE_SET_PITCH_RATE
Definition Opcodes.hpp:1247
@ SMSG_MOVE_UPDATE_TELEPORT
Definition Opcodes.hpp:1693
@ SMSG_INITIALIZE_FACTIONS
Definition Opcodes.hpp:334
@ SMSG_FORCE_RUN_SPEED_CHANGE
Definition Opcodes.hpp:269
@ SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
Definition Opcodes.hpp:800
@ SMSG_LOOT_RESPONSE
Definition Opcodes.hpp:397
@ SMSG_MESSAGECHAT
Definition Opcodes.hpp:187
@ SMSG_FORCE_RUN_BACK_SPEED_CHANGE
Definition Opcodes.hpp:271
@ SMSG_SET_FORCED_REACTIONS
Definition Opcodes.hpp:740
@ SMSG_SETUP_CURRENCY
Definition Opcodes.hpp:1660
@ SMSG_WORLD_SERVER_INFO
Definition Opcodes.hpp:1767
@ SMSG_FORCE_FLIGHT_SPEED_CHANGE
Definition Opcodes.hpp:979
@ SMSG_LOOT_LIST
Definition Opcodes.hpp:1100
@ SMSG_BATTLE_PET_JOURNAL
Definition Opcodes.hpp:1771
@ SMSG_FORCE_SWIM_SPEED_CHANGE
Definition Opcodes.hpp:273
@ SMSG_RAID_INSTANCE_INFO
Definition Opcodes.hpp:783
@ SMSG_COMPRESSED_UPDATE_OBJECT
Definition Opcodes.hpp:557
@ SMSG_UPDATE_INSTANCE_OWNERSHIP
Definition Opcodes.hpp:892
@ MSG_MOVE_SET_RUN_SPEED
Definition Opcodes.hpp:243
@ SMSG_INSTANCE_RESET_FAILED
Definition Opcodes.hpp:870
@ SMSG_UPDATE_COMBO_POINTS
Definition Opcodes.hpp:1007
@ MSG_MOVE_SET_FLIGHT_SPEED
Definition Opcodes.hpp:975
@ MSG_MOVE_SET_WALK_SPEED
Definition Opcodes.hpp:249
@ SMSG_EQUIPMENT_SET_SAVED
Definition Opcodes.hpp:1152
@ SMSG_UPDATE_OBJECT
Definition Opcodes.hpp:206
@ MSG_MOVE_SET_SWIM_SPEED
Definition Opcodes.hpp:252
@ MSG_MOVE_TELEPORT
Definition Opcodes.hpp:234
@ SMSG_UPDATE_ACTION_BUTTONS
Definition Opcodes.hpp:341
@ MSG_MOVE_SET_FLIGHT_BACK_SPEED
Definition Opcodes.hpp:977
@ SMSG_CANCEL_AUTO_REPEAT
Definition Opcodes.hpp:731
@ MSG_MOVE_TELEPORT_ACK
Definition Opcodes.hpp:236
@ SMSG_INIT_WORLD_STATES
Definition Opcodes.hpp:773
@ SMSG_MOVE_SET_ACTIVE_MOVER
Definition Opcodes.hpp:1687
@ SMSG_RESET_FAILED_NOTIFY
Definition Opcodes.hpp:1000
@ SMSG_UPDATE_LAST_INSTANCE
Definition Opcodes.hpp:871
@ SMSG_FORCE_PITCH_RATE_CHANGE
Definition Opcodes.hpp:1248
@ SMSG_UPDATE_TALENT_DATA
Definition Opcodes.hpp:1348
@ SMSG_EQUIPMENT_SET_LIST
Definition Opcodes.hpp:1344
@ SMSG_INSTANCE_SAVE_CREATED
Definition Opcodes.hpp:782
@ SMSG_LOAD_CUF_PROFILES
Definition Opcodes.hpp:1679
@ MSG_MOVE_SET_RUN_BACK_SPEED
Definition Opcodes.hpp:246
@ PET_WATER_ELEMENTAL_NEW
@ PET_SPELL_STATE_DEFAULT
@ PET_TYPE_HUNTER
@ PET_SLOT_LAST_STABLE_SLOT
@ PET_SLOT_FIRST_STABLE_SLOT
@ PET_SLOT_MAX_ACTIVE_SLOT
@ PET_SLOT_FIRST_ACTIVE_SLOT
RankTitles
@ ACCOUNT_FLAG_XPACK_01
@ ACCOUNT_FLAG_XPACK_02
@ GS_MASK_5
@ GS_MASK_4
@ GS_MASK_LEVEL_75
@ GS_MASK_6
@ GS_MASK_3
@ GS_MASK_LEVEL_25
@ GS_MASK_LEVEL_50
@ GS_MASK_1
@ GS_MASK_2
@ DUEL_STATE_FINISHED
@ DUEL_STATE_REQUESTED
@ DUEL_STATE_STARTED
const time_t forcedResurrectInterval
std::map< uint8_t, std::unique_ptr< PetCache > > PetCacheMap
@ STANDING_HONORED
@ STANDING_HATED
@ STANDING_REVERED
@ STANDING_HOSTILE
@ STANDING_FRIENDLY
@ STANDING_NEUTRAL
@ STANDING_EXALTED
@ STANDING_UNFRIENDLY
@ GENDER_MALE
@ GENDER_FEMALE
LoginFlags
@ LOGIN_NO_FLAG
@ COOLDOWN_TYPE_SPELL
@ COOLDOWN_TYPE_CATEGORY
@ NUM_COOLDOWN_TYPES
PlayerBytes3_DrunkValue
@ DRUNKEN_TIPSY
@ DRUNKEN_DRUNK
@ DRUNKEN_SOBER
@ DRUNKEN_SMASHED
@ RESTSTATE_RESTED
@ RESTSTATE_NORMAL
@ NUM_ARENA_TEAM_TYPES
@ TRADE_STATUS_CANCELLED
PlayerTeam
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ PLAYER_MISC_FLAG_SHOW_RELEASE_TIME
@ PLAYER_FLAG_RESTING
@ PLAYER_FLAG_DEATH_WORLD_ENABLE
@ PLAYER_FLAG_AFK
@ PLAYER_FLAG_PVP_TOGGLE
@ PLAYER_FLAG_PARTY_LEADER
@ PLAYER_FLAG_PVP_GUARD_ATTACKABLE
@ PLAYER_FLAG_GM
@ PLAYER_FLAG_DND
@ UNDERWATERSTATE_LAVA
@ UNDERWATERSTATE_SWIMMING
@ UNDERWATERSTATE_UNDERWATER
MirrorTimerTypes
@ MIRROR_TYPE_BREATH
@ MIRROR_TYPE_FATIGUE
@ MIRROR_TYPE_FIRE
std::unordered_set< uint32_t > SpellSet
@ FACTION_FLAG_INACTIVE
@ FACTION_FLAG_HIDDEN
@ FACTION_FLAG_FORCED_INVISIBLE
@ FACTION_FLAG_VISIBLE
@ FACTION_FLAG_AT_WAR
@ FACTION_FLAG_DISABLE_ATWAR
@ PLAYER_CHEAT_CAST_TIME
@ PLAYER_CHEAT_NONE
@ PLAYER_CHEAT_AURA_STACK
@ PLAYER_CHEAT_FLY
@ PLAYER_CHEAT_POWER
@ PLAYER_CHEAT_ITEM_STACK
@ PLAYER_CHEAT_COOLDOWN
@ PLAYER_CHEAT_TAXI
@ PLAYER_CHEAT_TRIGGERPASS
@ PLAYER_CHEAT_GOD_MODE
static uint8_t getSideByRace(uint8_t race)
PlayerCombatRating
@ CR_EXPERTISE
@ CR_HIT_TAKEN_MELEE
@ CR_WEAPON_SKILL_RANGED
@ CR_HASTE_RANGED
@ CR_HIT_MELEE
@ CR_RESILIENCE_PLAYER_DAMAGE_TAKEN
@ CR_CRIT_TAKEN_SPELL
@ CR_ARMOR_PENETRATION
@ CR_CRIT_MELEE
@ CR_CRIT_RANGED
@ CR_HIT_TAKEN_SPELL
@ CR_PARRY
@ CR_WEAPON_SKILL_OFFHAND
@ CR_DODGE
@ CR_DEFENSE_SKILL
@ MAX_PCR
@ CR_HASTE_MELEE
@ CR_BLOCK
@ CR_WEAPON_SKILL_MAINHAND
@ CR_HASTE_SPELL
@ CR_RESILIENCE_CRIT_TAKEN
@ CR_HIT_SPELL
@ CR_HIT_TAKEN_RANGED
@ CR_CRIT_SPELL
@ CR_HIT_RANGED
uint32_t getAEVersion()
@ MAGE
@ MAX_PLAYER_CLASSES
@ HUNTER
@ DEATHKNIGHT
@ ROGUE
@ WARLOCK
@ PRIEST
@ PALADIN
@ DRUID
@ WARRIOR
@ SHAMAN
@ FRIEND_IGNORE_REMOVED
@ FRIEND_ONLINE
@ FRIEND_ENEMY
@ FRIEND_ALREADY
@ FRIEND_ADDED_OFFLINE
@ FRIEND_NOT_FOUND
@ FRIEND_ADDED_ONLINE
@ FRIEND_IGNORE_ADDED
@ FRIEND_IGNORE_NOT_FOUND
@ FRIEND_IGNORE_SELF
@ FRIEND_IGNORE_ALREADY
@ FRIEND_SELF
@ FRIEND_REMOVED
@ FRIEND_OFFLINE
@ RACE_TROLL
@ RACE_UNDEAD
@ RACE_PANDAREN_NEUTRAL
@ RACE_ORC
@ RACE_DRAENEI
@ RACE_NIGHTELF
@ RACE_BLOODELF
@ RACE_DWARF
@ RACE_GNOME
@ RACE_GOBLIN
@ RACE_HUMAN
@ RACE_WORGEN
@ RACE_PANDAREN_ALLIANCE
@ RACE_PANDAREN_HORDE
@ RACE_TAUREN
@ TRANSFER_PENDING
@ DUEL_WINNER_RETREAT
@ LOOT_FISHING_JUNK
@ LOOT_CORPSE
@ LOOT_FISHING
@ LOOT_SKINNING
@ LOOT_FISHINGHOLE
@ DUEL_STATUS_INBOUNDS
@ DUEL_STATUS_OUTOFBOUNDS
CharterTypes
@ NUM_CHARTER_TYPES
@ CHARTER_TYPE_GUILD
@ CHARTER_TYPE_ARENA_2V2
#define GLYPHS_COUNT
#define COOLDOWN_SKIP_SAVE_IF_MS_LESS_THAN
#define LOGIN_CIENT_SEND_DELAY
#define DBC_PLAYER_SKILL_MAX
#define PLAYER_ACTION_BUTTON_COUNT
#define MAX_SPEC_COUNT
#define PLAYER_ACTION_BUTTON_SIZE
#define DBC_PLAYER_LEVEL_CAP
#define BASE_PARRY_CHANCE
#define MAX_QUEST_SLOT
#define PLAYER_HONORLESS_TARGET_SPELL
#define BASE_BLOCK_CHANCE
#define COLLISION_INDOOR_CHECK_INTERVAL
bool RankChanged(int32_t Standing, int32_t Change)
Definition Player.cpp:11359
bool CanToggleAtWar(uint8_t flag)
Definition Player.cpp:11314
bool Visible(uint8_t flag)
Definition Player.cpp:11317
bool RankChangedFlat(int32_t Standing, int32_t NewStanding)
Definition Player.cpp:11364
bool ForcedInvisible(uint8_t flag)
Definition Player.cpp:11316
bool SetFlagAtWar(uint8_t &flag, bool set)
Definition Player.cpp:11321
bool Inactive(uint8_t flag)
Definition Player.cpp:11319
bool Hidden(uint8_t flag)
Definition Player.cpp:11318
bool SetFlagVisible(uint8_t &flag, bool set)
Definition Player.cpp:11333
bool SetFlagInactive(uint8_t &flag, bool set)
Definition Player.cpp:11347
bool AtWar(uint8_t flag)
Definition Player.cpp:11315
PowerType
Definition PowerType.hpp:11
@ POWER_TYPE_SOUL_SHARDS
Definition PowerType.hpp:27
@ POWER_TYPE_RUNES
Definition PowerType.hpp:23
@ POWER_TYPE_RUNIC_POWER
Definition PowerType.hpp:24
@ POWER_TYPE_FOCUS
Definition PowerType.hpp:15
@ POWER_TYPE_RAGE
Definition PowerType.hpp:14
@ POWER_TYPE_MANA
Definition PowerType.hpp:13
@ TOTAL_PLAYER_POWER_TYPES
Definition PowerType.hpp:38
@ POWER_TYPE_HOLY_POWER
Definition PowerType.hpp:29
@ POWER_TYPE_ENERGY
Definition PowerType.hpp:16
@ POWER_TYPE_ECLIPSE
Definition PowerType.hpp:28
@ EXTRA_PROC_NULL
Definition ProcFlags.hpp:48
@ EXTRA_PROC_ON_MAIN_HAND_HIT_ONLY
Definition ProcFlags.hpp:49
@ EXTRA_PROC_ON_OFF_HAND_HIT_ONLY
Definition ProcFlags.hpp:50
SpellProcFlags
Definition ProcFlags.hpp:11
@ PROC_ON_DONE_MELEE_HIT
Definition ProcFlags.hpp:16
@ PROC_ON_DONE_RANGED_HIT
Definition ProcFlags.hpp:21
@ PROC_ON_DONE_OFFHAND_ATTACK
Definition ProcFlags.hpp:41
@ PROC_ON_DONE_MELEE_SPELL_HIT
Definition ProcFlags.hpp:18
@ PROC_ON_DONE_RANGED_SPELL_HIT
Definition ProcFlags.hpp:23
@ INVALID_REASON_HAVE_TIMED_QUEST
@ FAILED_REASON_INV_FULL
#define MAX_QUEST_LOG_SIZE
#define sQuestMgr
Definition QuestMgr.h:252
#define MAX_REQUIRED_QUEST_ITEM
@ SCHOOL_FIRE
Definition School.hpp:14
@ SCHOOL_SHADOW
Definition School.hpp:17
@ TOTAL_SPELL_SCHOOLS
Definition School.hpp:19
@ SCHOOL_NORMAL
Definition School.hpp:12
@ SCHOOL_NATURE
Definition School.hpp:15
@ SCHOOL_ARCANE
Definition School.hpp:18
@ SCHOOL_FROST
Definition School.hpp:16
@ SCHOOL_HOLY
Definition School.hpp:13
@ SKILL_LANG_GNOMISH
Definition Skill.hpp:121
@ SKILL_POISONS
Definition Skill.hpp:22
@ SKILL_PET_HYDRA
Definition Skill.hpp:234
@ SKILL_DUAL_WIELD
Definition Skill.hpp:45
@ SKILL_LANG_COMMON
Definition Skill.hpp:39
@ SKILL_LANG_PANDAREN_NEUTRAL
Definition Skill.hpp:243
@ SKILL_DEFENSE
Definition Skill.hpp:38
@ SKILL_LANG_DRAENEI
Definition Skill.hpp:168
@ SKILL_DIREHORN
Definition Skill.hpp:272
@ SKILL_LANG_ORCISH
Definition Skill.hpp:41
@ SKILL_LANG_TROLL
Definition Skill.hpp:122
@ SKILL_LANG_GUTTERSPEAK
Definition Skill.hpp:157
@ SKILL_LANG_OLD_TONGUE
Definition Skill.hpp:58
@ SKILL_LANG_TAURAHE
Definition Skill.hpp:44
@ SKILL_LANG_PANDAREN_ALLIANCE
Definition Skill.hpp:244
@ SKILL_LANG_TITAN
Definition Skill.hpp:57
@ SKILL_LANG_DARNASSIAN
Definition Skill.hpp:43
@ SKILL_SWORDS
Definition Skill.hpp:24
@ SKILL_LANG_DEMON_TONGUE
Definition Skill.hpp:56
@ SKILL_LANG_DWARVEN
Definition Skill.hpp:42
@ SKILL_RIDING
Definition Skill.hpp:163
@ SKILL_LANG_THALASSIAN
Definition Skill.hpp:54
@ SKILL_LANG_GILNEAN
Definition Skill.hpp:207
@ SKILL_LOCKPICKING
Definition Skill.hpp:151
@ SKILL_LANG_PANDAREN_HORDE
Definition Skill.hpp:245
@ SKILL_LANG_DRACONIC
Definition Skill.hpp:55
@ SKILL_FROST
Definition Skill.hpp:15
@ SKILL_LANG_GOBLIN
Definition Skill.hpp:208
@ SKILL_TYPE_SECONDARY
Definition Skill.hpp:282
@ SKILL_TYPE_LANGUAGE
Definition Skill.hpp:283
@ SKILL_TYPE_PROFESSION
Definition Skill.hpp:284
@ SKILL_TYPE_WEAPON
Definition Skill.hpp:279
@ SPEC_SECONDARY
Definition Spec.hpp:11
@ SPEC_PRIMARY
Definition Spec.hpp:10
@ SPELL_DMG_TYPE_MAGIC
@ SPELL_VISUAL_DRINK
@ SPELL_VISUAL_FOOD
@ ATTRIBUTESEXB_NOT_NEED_SHAPESHIFT
@ ATTRIBUTESEX_AUTOCASTED_AT_SPELL_LEARN
@ ATTRIBUTESEX_NO_INITIAL_AGGRO
@ ATTRIBUTES_RANGED
@ ATTRIBUTES_ABILITY
@ ATTRIBUTES_TRIGGER_COOLDOWN
@ ATTRIBUTES_ONLY_OUTDOORS
@ SPELL_EFFECT_ADD_FARSIGHT
@ SPELL_EFFECT_APPLY_GROUP_AREA_AURA
@ SPELL_EFFECT_PROFICIENCY
@ SPELL_EFFECT_SKILL
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_EFFECT_DUAL_WIELD_2H
@ SPELL_EFFECT_TRADE_SKILL
@ SPELL_EFFECT_NULL
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_DUAL_WIELD
@ SPELL_EFFECT_APPLY_RAID_AREA_AURA
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_APPLY_AURA
@ SPELL_CAST_SUCCESS
@ SPELL_FAILED_SPELL_UNAVAILABLE
@ SPELL_FLAG_IS_EXPIREING_ON_PET
@ SPELL_FLAG_IS_CASTED_ON_PET_SUMMON_PET_OWNER
@ SPELL_FLAG_IS_CASTED_ON_PET_SUMMON_ON_PET
@ SPELL_FLAG_IS_EXPIREING_WITH_PET
@ MECHANIC_MOUNTED
std::pair< SpellAreaMap::const_iterator, SpellAreaMap::const_iterator > SpellAreaMapBounds
Definition SpellMgr.hpp:59
std::pair< SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator > SpellAreaForAreaMapBounds
Definition SpellMgr.hpp:62
#define sSpellMgr
Definition SpellMgr.hpp:197
std::pair< SpellAreaForQuestMap::const_iterator, SpellAreaForQuestMap::const_iterator > SpellAreaForQuestMapBounds
Definition SpellMgr.hpp:60
@ SPELLMOD_COOLDOWN_DECREASE
@ SPELLMOD_GLOBAL_COOLDOWN
@ STAT_SPIRIT
Definition Stats.h:37
@ STAT_INTELLECT
Definition Stats.h:36
@ STAT_COUNT
Definition Stats.h:38
@ STAT_AGILITY
Definition Stats.h:34
@ STAT_STRENGTH
Definition Stats.h:33
@ STAT_STAMINA
Definition Stats.h:35
int ZEXPORT deflateEnd(z_streamp strm)
Definition deflate.c:895
int ZEXPORT deflate(z_streamp strm, int flush)
Definition deflate.c:582
Byte FAR Bytef
Definition zconf.h:342
#define Z_STREAM_END
Definition zlib.h:174
#define Z_FINISH
Definition zlib.h:168
#define Z_OK
Definition zlib.h:173
#define Z_NO_FLUSH
Definition zlib.h:164
#define deflateInit(strm, level)
Definition zlib.h:1546
#define true
Definition StormPort.h:32
#define false
Definition StormPort.h:33
@ SUMMON_TYPE_COMPANION
#define sTaxiMgr
Definition TaxiMgr.hpp:156
#define sTicketMgr
Definition TicketMgr.hpp:97
#define sTransportHandler
@ EMOTE_ONESHOT_NONE
UnitSpeedType
@ TYPE_RUN_BACK
@ TYPE_SWIM_BACK
@ TYPE_SWIM
@ TYPE_WALK
@ TYPE_RUN
@ TYPE_TURN_RATE
@ TYPE_FLY_BACK
@ TYPE_PITCH_RATE
@ TYPE_FLY
@ UNIT_FLAG2_ENABLE_POWER_REGEN
@ POS_AURA_LIMIT_PVP_ATTACKABLE
@ UNIT_FLAG_MOUNTED_TAXI
@ UNIT_FLAG_PVP
@ UNIT_FLAG_PVP_ATTACKABLE
@ UNIT_FLAG_LOCK_PLAYER
@ UNIT_FLAG_LOOTING
@ UNIT_FLAG_SKINNABLE
@ INVIS_FLAG_DRUNK
DeathState
@ CORPSE
@ ALIVE
@ JUST_DIED
@ DAMAGE_LAVA
@ DAMAGE_DROWNING
@ U_DYN_FLAG_LOOTABLE
@ U_DYN_FLAG_TAPPED_BY_PLAYER
@ REGENERATION_INTERVAL_HOLY_POWER
@ UNIT_STATE_ROOTED
@ UNIT_STATE_IN_FLIGHT
@ UNIT_STATE_POLYMORPHED
@ UNIT_STATE_STUNNED
UnitBytes_ShapeshiftForm
@ FORM_DIREBEAR
@ FORM_SHADOW
@ FORM_BERSERKERSTANCE
@ FORM_DEFENSIVESTANCE
@ FORM_MOONKIN
@ FORM_CAT
@ FORM_STEALTH
@ FORM_BATTLESTANCE
@ FORM_NORMAL
@ FORM_BEAR
@ MELEE
@ RANGED
@ OFFHAND
#define getOffsetForStructuredField(s, m)
#define getOffsetForStructuredArrayField(s, m, index)
#define getSizeOfStructure(s)
static constexpr uint8_t MAX_SPELL_EFFECTS
SERVER_DECL WDB::WDBContainer< WDB::Structures::CreatureDisplayInfoExtraEntry > sCreatureDisplayInfoExtraStore
Definition WDBStores.cpp:69
SERVER_DECL WDB::WDBContainer< WDB::Structures::TalentEntry > sTalentStore
WDB::Structures::MapDifficulty const * getMapDifficultyData(uint32_t mapId, InstanceDifficulty::Difficulties difficulty)
SERVER_DECL WDB::WDBContainer< WDB::Structures::ChrRacesEntry > sChrRacesStore
Definition WDBStores.cpp:66
SERVER_DECL WDB::WDBContainer< WDB::Structures::GtChanceToMeleeCritEntry > sGtChanceToMeleeCritStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::GlyphPropertiesEntry > sGlyphPropertiesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::SummonPropertiesEntry > sSummonPropertiesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::MapEntry > sMapStore
Definition WDBStores.cpp:91
SERVER_DECL WDB::WDBContainer< WDB::Structures::SkillLineEntry > sSkillLineStore
Definition WDBStores.cpp:97
TaxiPathNodesByPath sTaxiPathNodesByPath
SERVER_DECL WDB::WDBContainer< WDB::Structures::ItemSetEntry > sItemSetStore
Definition WDBStores.cpp:84
SERVER_DECL WDB::WDBContainer< WDB::Structures::GtChanceToMeleeCritBaseEntry > sGtChanceToMeleeCritBaseStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::CurrencyTypesEntry > sCurrencyTypesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::ItemEntry > sItemStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::TaxiPathEntry > sTaxiPathStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::GtCombatRatingsEntry > sGtCombatRatingsStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::CreatureDisplayInfoEntry > sCreatureDisplayInfoStore
Definition WDBStores.cpp:68
SERVER_DECL WDB::WDBContainer< WDB::Structures::PhaseEntry > sPhaseStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::CreatureModelDataEntry > sCreatureModelDataStore
Definition WDBStores.cpp:70
SERVER_DECL WDB::WDBContainer< WDB::Structures::ChrClassesEntry > sChrClassesStore
Definition WDBStores.cpp:65
SERVER_DECL WDB::WDBContainer< WDB::Structures::GtChanceToSpellCritBaseEntry > sGtChanceToSpellCritBaseStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::FactionEntry > sFactionStore
Definition WDBStores.cpp:79
SERVER_DECL WDB::WDBContainer< WDB::Structures::ScalingStatValuesEntry > sScalingStatValuesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::ChatChannelsEntry > sChatChannelsStore
Definition WDBStores.cpp:61
SERVER_DECL WDB::WDBContainer< WDB::Structures::GtChanceToSpellCritEntry > sGtChanceToSpellCritStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::WorldMapOverlayEntry > sWorldMapOverlayStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::NumTalentsAtLevel > sNumTalentsAtLevel
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellShapeshiftFormEntry > sSpellShapeshiftFormStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::WorldMapAreaEntry > sWorldMapAreaStore
WDB::Structures::MapDifficulty const * getDownscaledMapDifficultyData(uint32_t mapId, InstanceDifficulty::Difficulties &difficulty)
SERVER_DECL WDB::WDBContainer< WDB::Structures::GlyphSlotEntry > sGlyphSlotStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::TaxiNodesEntry > sTaxiNodesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::TalentTabEntry > sTalentTabStore
WDB::Structures::CharStartOutfitEntry const * getStartOutfitByRaceClass(uint8_t race, uint8_t class_, uint8_t gender)
SERVER_DECL WDB::WDBContainer< WDB::Structures::ScalingStatDistributionEntry > sScalingStatDistributionStore
std::vector< WDB::Structures::TaxiPathNodeEntry const * > TaxiPathNodeList
@ MAP_RAID
#define OUTFIT_ITEMS
#define sWeatherMgr
@ HIGHGUID_TYPE_GUILD
Definition WoWGuid.h:52
static constexpr uint8_t WOWPLAYER_EXPLORED_ZONES_COUNT
Definition WoWPlayer.hpp:75
static constexpr uint8_t WOWPLAYER_SKILL_INFO_COUNT
Definition WoWPlayer.hpp:74
@ INTRATE_PVPTIMER
Definition WorldConfig.h:50
@ INTRATE_COMPRESSION
Definition WorldConfig.h:49
@ INTRATE_SAVE
Definition WorldConfig.h:48
@ RATE_EXPLOREXP
Definition WorldConfig.h:33
@ RATE_KILLREPUTATION
Definition WorldConfig.h:36
@ RATE_RESTXP
Definition WorldConfig.h:31
#define sCheatLog
static void FastGUIDPack(ByteBuffer &buf, const uint64_t &oldguid)
@ SS_MUST_HAVE_BC
@ SS_BANNED_FOR_TIME
@ SS_BG_REMOVE_QUEUE_INF
@ SS_MUST_HAVE_WOTLK
@ SS_NOT_ALLOWED_TO_PLAY
#define sWorld
Definition World.h:244
#define worldConfig
Definition World.h:245
static const unsigned char map[256]
bool hideWayPoints(Player *player)
void eventOnTargetDied(Object *pKiller)
we have to tell our current enemies to stop attacking us, we should also forget about our targets
bool SavetoDB(QueryBuffer *buf)
void FillEquipmentSetListPacket(WorldPacket &data)
bool LoadfromDB(QueryResult *result)
std::string m_name
Definition ArenaTeam.hpp:93
virtual std::unique_ptr< WorldPacket > serialise()
void removeAura(AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
uint32_t getMapId() const
Definition BaseMap.cpp:66
bool isInstanceableMap() const
Definition BaseMap.cpp:124
bool isBattlegroundOrArena() const
Definition BaseMap.cpp:103
Battleground * getBattleground()
virtual bool CreateCorpse(Player *plr)
virtual void OnAddPlayer(Player *plr)=0
void portPlayer(Player *plr, bool skip_teleport=false)
virtual bool HookHandleRepop(Player *plr)=0
virtual void HookOnPlayerDeath(Player *plr)=0
WorldMap * getWorldMap()
virtual void HookOnUnitDied(Unit *victim)
void removePlayer(Player *plr, bool logout)
void removePendingPlayer(Player *plr)
virtual void HookOnPlayerResurrect(Player *player)
void onPlayerPushed(Player *plr)
void flushBits()
Definition ByteBuffer.h:93
void put(size_t pos, T value)
Definition ByteBuffer.h:201
void writeBits(T value, size_t bits)
Definition ByteBuffer.h:119
size_t bitwpos() const
Definition ByteBuffer.h:433
void PutBits(size_t pos, T value, uint32_t bitCount)
Definition ByteBuffer.h:601
void append(T value)
Definition ByteBuffer.h:78
void WriteByteSeq(uint8_t b)
Definition ByteBuffer.h:182
bool writeBit(uint32_t bit)
Definition ByteBuffer.h:103
size_t wpos()
Definition ByteBuffer.h:422
void attemptJoin(Player *plr, std::string password, bool skipCheck=false)
Definition Channel.cpp:85
bool hasMember(Player *pPlayer) const
Definition Channel.cpp:179
void leaveChannel(Player *plr, bool sendPacket=true)
Definition Channel.cpp:138
uint8_t getCharterType() const
Definition Charter.cpp:76
Item * getItem(int16_t slot)
virtual void onQuestAccept(Player *, QuestProperties const *)
CreatureAIScript * GetScript()
bool HasQuest(uint32_t id, uint32_t type)
bool isTaxi() const
Definition Creature.cpp:259
CreatureProperties const * GetCreatureProperties()
Player * m_escorter
Definition Creature.h:356
bool isQuestGiver() const
Definition Creature.cpp:257
uint8_t asUint8(bool _silencedError=false) const
Definition Field.cpp:18
uint64_t asUint64(bool _silencedError=false) const
Definition Field.cpp:27
const char * asCString() const
Definition Field.cpp:13
bool asBool() const
Definition Field.cpp:16
uint16_t asUint16(bool _silencedError=false) const
Definition Field.cpp:21
uint32_t asUint32(bool _silencedError=false) const
Definition Field.cpp:24
uint16_t getLootMode() const
void getFishLoot(Player *loot_owner, bool getJunk=false)
uint32_t getLootGenerationTime() const
uint32_t getRespawnDelay() const
Definition GameObject.h:69
LootState getLootState() const
uint64_t getCreatedByGuid() const
time_t getRespawnTime() const
Definition GameObject.h:66
bool isSpawnedByDefault() const
Definition GameObject.h:77
void RemoveFromWorld(bool free_guid)
Remove object from world.
void despawn(uint32_t delay, uint32_t forceRespawntime)
GameObjectProperties const * GetGameObjectProperties() const
void setLootState(LootState state, Unit *unit=nullptr)
Definition Group.h:160
void SendPacketToAll(WorldPacket *packet)
Definition Group.h:180
uint32_t GetID()
Definition Group.h:223
CachedCharacterInfo * GetLeader(void)
Definition Group.h:205
void UpdateAllOutOfRangePlayersFor(Player *pPlayer)
Definition Group.cpp:1033
void Update()
Definition Group.cpp:199
void UpdateOutOfRangePlayer(Player *pPlayer, bool Distribute, WorldPacket *Packet)
Definition Group.cpp:837
void sendGroupLoot(Loot *loot, Object *object, Player *plr, uint32_t mapId)
Definition Group.cpp:1423
void RemovePlayer(CachedCharacterInfo *info)
Definition Group.cpp:422
std::string const & getMOTD() const
Definition Guild.hpp:50
static int32_t CalculateHonorPointsForKill(uint32_t playerLevel, uint32_t victimLevel)
static void RecalculateHonorFields(Player *pPlayer)
bool canReset() const
uint32_t getMapId() const
bool removePlayer(Player *player)
uint32_t getInstanceId() const
void deleteFromDB()
virtual void OnZoneChange(Player *, uint32_t, uint32_t)
virtual void OnPlayerDeath(Player *, Unit *)
virtual void OnPlayerEnter(Player *)
uint32_t GetItemCount(uint32_t itemid, bool IncBank=false)
Finds item ammount on inventory, banks not included.
Item * SafeAddItem(uint32_t ItemId, int8_t ContainerSlot, int16_t slot)
Creates and adds a item that can be manipulated after.
Item * GetInventoryItem(int16_t slot)
Gets a item from Inventory.
void mLoadItemsFromDatabase(QueryResult *result)
Item Loading.
std::unique_ptr< Item > SafeRemoveAndRetreiveItemFromSlot(int8_t ContainerSlot, int16_t slot, bool destroy)
Removes the item safely and returns it back for usage.
bool AddItemById(uint32_t itemid, uint32_t count, int32_t randomprop)
Arcemu::EquipmentSetMgr m_EquipmentSets
SlotResult FindFreeInventorySlot(ItemProperties const *proto)
void HandleItemDurations()
Look for items with limited duration and send the remaining time to the client.
void buildInventoryChangeError(Item const *srcItem, Item const *dstItem, uint8_t inventoryError, uint32_t srcItemId=0)
uint32_t m_CreateForPlayer(ByteBuffer *data)
void sendEnchantDurations(Item const *forItem=nullptr)
void mSaveItemsToDatabase(bool first, QueryBuffer *buf)
Item saving.
bool IsEquipped(uint32_t itemid)
Item * GetItemByGUID(uint64_t itemGuid)
Gets a Item by guid.
void addTradeableItem(Item *item)
void update(uint32_t timePassed)
Item * FindItemLessMax(uint32_t itemid, uint32_t cnt, bool IncBank)
Checks for stacks that didn't reached max capacity.
int8_t GetItemSlotByType(uint32_t type)
std::tuple< AddItemResult, std::unique_ptr< Item > > AddItemToFreeSlot(std::unique_ptr< Item > item)
Adds a Item to a free slot.
Definition Item.hpp:43
void applyAllEnchantmentBonuses()
Definition Item.cpp:389
void removeEnchantment(EnchantmentSlot slot, bool timerExpired=false)
Definition Item.cpp:362
uint32_t getDurability() const
Definition Item.cpp:216
static uint32_t generateRandomSuffixFactor(ItemProperties const *m_itemProto)
Definition Item.cpp:735
void removeAllEnchantments(bool onlyTemporary)
Definition Item.cpp:407
uint32_t getMaxDurability() const
Definition Item.cpp:219
void setStackCount(uint32_t count)
Definition Item.cpp:144
ItemProperties const * getItemProperties() const
Definition Item.cpp:954
int32_t getReforgableStat(ItemModType statType) const
Definition Item.cpp:1170
void removeFromWorld()
Definition Item.cpp:1514
uint32_t getVisibleEntry() const
Definition Item.cpp:998
uint32_t getEnchantmentId(uint8_t index) const
Definition Item.cpp:193
void removeAllEnchantmentBonuses()
Definition Item.cpp:398
std::unique_ptr< Loot > m_loot
Definition Item.hpp:256
bool isWeapon() const
Definition Item.hpp:220
void applyRandomProperties(bool apply)
Definition Item.cpp:671
uint8_t getSocketSlotCount(bool includePrismatic=true) const
Definition Item.cpp:824
EnchantmentInstance * getEnchantment(EnchantmentSlot slot)
Definition Item.cpp:252
void ChangeCoords(const LocationVector &src)
float distanceSquare(const LocationVector &comp) const
static WDB::Structures::AreaTableEntry const * GetAreaById(uint32_t area_id)
WDB::Structures::FactionEntry const * m_factionEntry
Definition Object.hpp:647
bool isValidTarget(Object *target, SpellInfo const *bySpell=nullptr)
Definition Object.cpp:4073
Creature * getWorldMapCreature(const uint64_t &guid) const
Definition Object.cpp:4597
void BuildFieldUpdatePacket(Player *Target, uint32_t Index, uint32_t Value)
Definition Object.cpp:1782
void setScale(float scaleX)
Definition Object.cpp:408
float GetTransOffsetY() const
Definition Object.hpp:382
uint64_t getGuid() const
Definition Object.cpp:295
LocationVector GetPosition() const
Definition Object.hpp:373
float CalcDistance(Object *Ob)
Definition Object.cpp:3555
virtual void setCreateBits(UpdateMask *updateMask, Player *target) const
Definition Object.cpp:3442
const uint32_t & getAreaId() const
Definition Object.hpp:470
void SetInstanceID(int32_t instance)
Definition Object.hpp:663
bool isOutdoors() const
Definition Object.hpp:472
const float & GetOrientation() const
Definition Object.hpp:357
uint32_t m_mapId
Definition Object.hpp:734
bool IsInWorld() const
Definition Object.hpp:98
bool IsWithinDistInMap(Object *obj, const float dist2compare) const
Definition Object.cpp:3592
void removeDynamicFlags(uint16_t dynamicFlags)
Definition Object.cpp:396
void interruptSpell(uint32_t spellId=0, bool checkMeleeSpell=true)
Definition Object.cpp:701
virtual void setUpdateBits(UpdateMask *updateMask, Player *target) const
Definition Object.cpp:3437
int32_t GetInstanceID()
Definition Object.hpp:664
float GetTransOffsetX() const
Definition Object.hpp:381
MovementInfo obj_movement_info
Definition Object.hpp:632
bool isHostileTo(Object *target)
Definition Object.cpp:4031
LocationVector m_position
Definition Object.hpp:744
void setZoneId(uint32_t newZone)
Definition Object.cpp:4396
WorldMap * m_WorldMap
Definition Object.hpp:736
Unit * getWorldMapUnit(const uint64_t &guid) const
Definition Object.cpp:4578
bool isInFront(Object *target)
Definition Object.cpp:3766
virtual uint32_t buildCreateUpdateBlockForPlayer(ByteBuffer *data, Player *target)
This includes any nested objects we have, inventory for example.
Definition Object.cpp:421
uint32_t m_phase
Definition Object.hpp:634
void setGuidLow(uint32_t low)
Definition Object.cpp:305
std::vector< Object * > getInRangeObjectsSet() const
Definition Object.cpp:1573
void setDynamicFlags(uint16_t dynamicFlags)
Definition Object.cpp:394
::WDB::Structures::AreaTableEntry const * GetArea() const
Definition Object.cpp:1766
Transporter * GetTransport() const
Definition Object.hpp:379
std::vector< Object * > getInRangePlayersSet() const
Definition Object.cpp:1617
bool isCastingSpell(bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false) const
Definition Object.cpp:735
uint32_t m_zoneId
Definition Object.hpp:731
float calcRadAngle(float Position1X, float Position1Y, float Position2X, float Position2Y)
Definition Object.cpp:3700
void setObjectType(uint8_t objectTypeId)
Definition Object.cpp:348
UpdateMask m_updateMask
Definition Object.hpp:752
uint32_t GetMapId() const
Definition Object.hpp:468
const float & GetPositionX() const
Definition Object.hpp:354
Player * getWorldMapPlayer(const uint64_t &guid) const
Definition Object.cpp:4586
void setGuid(uint64_t guid)
Definition Object.cpp:296
virtual bool isTransporter() const
Definition Object.hpp:207
bool write(const uint8_t &member, uint8_t val, bool skipObjectUpdate=false)
Definition Object.cpp:106
uint32_t GetTeam() const
Definition Object.cpp:4417
int32_t m_instanceId
Definition Object.hpp:757
uint32_t * m_uint32Values
Definition Object.hpp:120
WorldMap * getWorldMap() const
Definition Object.hpp:454
GameObject * ToGameObject()
Definition Object.hpp:399
const float & GetPositionZ() const
Definition Object.hpp:356
bool isGameObject() const
Definition Object.cpp:572
void interruptSpellWithSpellType(CurrentSpellType spellType)
Definition Object.cpp:713
const WoWGuid & GetNewGUID() const
Definition Object.hpp:335
bool isContainer() const
Definition Object.cpp:574
float GetTransOffsetZ() const
Definition Object.hpp:383
virtual bool isPet() const
Definition Object.hpp:203
uint16_t m_valuesCount
Definition Object.hpp:749
float GetTransOffsetO() const
Definition Object.hpp:384
uint8_t getObjectTypeId() const
Definition Object.cpp:566
bool isObjectInInRangeOppositeFactionSet(Object *pObj) const
Definition Object.cpp:1633
Creature * ToCreature()
Definition Object.hpp:393
uint32_t GetPhase() const
Definition Object.hpp:636
bool isPlayer() const
Definition Object.cpp:569
uint32_t m_areaId
Definition Object.hpp:732
uint16_t m_objectType
Definition Object.hpp:719
bool isItem() const
Definition Object.cpp:571
bool isCreatureOrPlayer() const
Definition Object.cpp:568
virtual void AddToWorld()
Definition Object.cpp:3449
virtual void RemoveFromWorld(bool free_guid)
Remove object from world.
Definition Object.cpp:3524
uint32_t getGuidLow() const
Definition Object.cpp:304
uint32_t getEntry() const
Definition Object.cpp:382
bool SetPosition(float newX, float newY, float newZ, float newOrientation, bool allowPorting=false)
Definition Object.cpp:3354
bool isCreature() const
Definition Object.cpp:570
float getDistance(Object const *obj) const
Definition Object.cpp:5040
Spell * getCurrentSpell(CurrentSpellType spellType) const
Definition Object.cpp:600
uint8_t m_objectTypeId
Definition Object.hpp:190
const WoWObject * objectData() const
Definition Object.hpp:123
const uint32_t & getZoneId() const
Definition Object.hpp:469
void addInRangeOppositeFaction(Object *obj)
Definition Object.cpp:1673
void SetMapId(uint32_t newMap)
Definition Object.hpp:464
float getExactDistSq(float x, float y, float z) const
Definition Object.hpp:415
uint16_t getDynamicFlags() const
Definition Object.cpp:386
const float & GetPositionY() const
Definition Object.hpp:355
Definition Pet.h:44
void SendTalentsToOwner()
Definition Pet.cpp:1774
uint8_t getPetId() const
Definition Pet.cpp:456
void unSummonTemporarily()
Definition Pet.cpp:416
void unSummon() override
Definition Pet.cpp:422
ActionButton & getActionButton(uint8_t slot)
void addTalent(uint32_t talentId, uint8_t rankId)
uint32_t getTalentPoints() const
void setTalentPoints(uint32_t points)
std::map< uint32_t, uint8_t > const & getTalents() const
uint32_t getLoginFlag() const
Definition Player.cpp:2642
CachedCharacterInfo * getPlayerInfo() const
Definition Player.cpp:2885
std::set< uint32_t > getFinishedQuests() const
Definition Player.cpp:9068
static Standing getReputationRankFromStanding(int32_t value)
Definition Player.cpp:11524
void setPlayerFlags(uint32_t flags)
Definition Player.cpp:769
uint32_t getBuybackPriceSlot(uint8_t slot) const
Definition Player.cpp:1242
void setInventorySlotItemGuid(uint8_t slot, uint64_t guid)
Definition Player.cpp:946
uint32_t getLevelGrouping()
Definition Player.cpp:8616
void setQuestLogExpireTimeBySlot(uint8_t slot, uint32_t expireTime)
Definition Player.cpp:917
void calculateDamage() override
Definition Player.cpp:16612
uint32_t getCombatRating(uint8_t combatRating) const
Definition Player.cpp:1276
uint32_t getNextLevelXp() const
Definition Player.cpp:997
uint32_t getGlyphsEnabled() const
Definition Player.cpp:1312
uint8_t getPvpRank() const
Definition Player.cpp:861
void initialiseArenaTeam()
Definition Player.cpp:8073
void setModDamageDoneNegative(uint16_t school, uint32_t value)
Definition Player.cpp:1206
float getRangedCritPercentage() const
Definition Player.cpp:1103
void leftChannel(Channel *channel)
Definition Player.cpp:7969
void clearCooldownForSpell(uint32_t spellId)
Definition Player.cpp:4422
bool canDualWield2H() const
Definition Player.cpp:4261
uint32_t m_flatStatModPos[5]
Definition Player.hpp:2070
float getSpellCritPercentage(uint8_t school) const
Definition Player.cpp:1110
Player * m_duelPlayer
Definition Player.hpp:1726
int32_t getBaseFactionStanding(uint32_t faction)
Definition Player.cpp:11440
void setTeam(uint32_t team)
Definition Player.cpp:2776
uint32_t getQueuedBgInstanceId() const
Definition Player.cpp:8556
bool m_firstLogin
Definition Player.hpp:1982
uint32_t m_underwaterMaxTime
Definition Player.hpp:584
void repopAtGraveyard(float ox, float oy, float oz, uint32_t mapId)
Definition Player.cpp:7622
bool isOnTaxi() const
Definition Player.cpp:10775
bool checkInstanceCount(uint32_t instanceId) const
Definition Player.cpp:13119
void modOffHandExpertise(int32_t value)
Definition Player.cpp:1097
void setResurrectMapId(uint32_t id)
Definition Player.cpp:7778
std::mutex m_tradeMutex
Definition Player.hpp:1052
void speedCheatReset()
Definition Player.cpp:9374
std::list< ItemSet > m_itemSets
Definition Player.hpp:1154
uint8_t getHairColor() const
Definition Player.cpp:833
void setGuildTimestamp(uint32_t timestamp)
Definition Player.cpp:874
void unSummonPetTemporarily()
Definition Player.cpp:12585
void setQuestLogEntryBySlot(uint8_t slot, uint32_t questEntry)
Definition Player.cpp:878
void eventDeath()
Definition Player.cpp:13784
bool m_isWaterBreathingEnabled
Definition Player.hpp:582
void sendSpellCooldownEventPacket(uint32_t spellId)
Definition Player.cpp:9676
WDB::Structures::ChrClassesEntry const * getDbcClassEntry()
Definition Player.cpp:2637
void _verifySkillValues(WDB::Structures::SkillLineEntry const *skillEntry, uint16_t *currentValue, uint16_t *maxValue, uint16_t *skillStep, bool *requireUpdate)
Definition Player.cpp:5700
void eventPortToGm(Player *gmPlayer)
Definition Player.cpp:2018
uint64_t getFarsightGuid() const
Definition Player.cpp:975
uint32_t getModDamageDonePositive(uint16_t school) const
Definition Player.cpp:1201
void setHairColor(uint8_t color)
Definition Player.cpp:834
uint8_t getPetCount() const
Definition Player.cpp:12323
bool m_isXpGainAllowed
Definition Player.hpp:1747
void repopRequest()
Definition Player.cpp:7545
uint16_t getSkillLineCurrent(uint16_t skillLine, bool includeBonus=true) const
Definition Player.cpp:4928
void setManaRegenerationWhileCasting(float value)
Definition Player.cpp:1146
void outPacket(uint16_t opcode, uint16_t length, const void *data) override
Definition Player.cpp:3155
void setXp(uint32_t xp)
Definition Player.cpp:994
void sendRaidDifficultyPacket()
Definition Player.cpp:9577
void onTalkReputation(WDB::Structures::FactionEntry const *factionEntry)
Definition Player.cpp:11689
bool isMoving() const
Definition Player.cpp:1510
uint32_t getTeleportState() const
Definition Player.cpp:1893
std::set< uint32_t > m_finishedDailies
Definition Player.hpp:1524
void zoneUpdate(uint32_t zoneId)
Definition Player.cpp:2097
uint32_t m_loadHealth
Definition Player.hpp:730
void softDisconnect()
Definition Player.cpp:3147
float getOffHandCritPercentage() const
Definition Player.cpp:1107
TradeData * getTradeData() const
Definition Player.cpp:6506
void sendPacket(WorldPacket *packet) override
Definition Player.cpp:3161
ItemInterface * getItemInterface() const
Definition Player.cpp:6934
void updateStats()
Definition Player.cpp:15532
float getMeleeCritPercentage() const
Definition Player.cpp:1100
bool loadSpells(QueryResult *result)
Definition Player.cpp:3846
void disableAppearing(bool disable)
Definition Player.cpp:2327
void setTrackCreature(uint32_t id)
Definition Player.cpp:1076
float_t calculateHealthRegenerationValue(bool inCombat) const
void sendInitialWorldstates()
Definition Player.cpp:9772
void setFace(uint8_t face)
Definition Player.cpp:828
uint32_t getXp() const
Definition Player.cpp:993
void sendDestroyObjectPacket(uint64_t destroyedGuid)
Definition Player.cpp:9611
void sendUpdateDataToSet(ByteBuffer *groupBuf, ByteBuffer *nonGroupBuf, bool sendToSelf)
Definition Player.cpp:10172
void addAuraVision(uint8_t auraVision)
void applyReforgeEnchantment(Item *item, bool apply)
Definition Player.cpp:9922
uint16_t m_foodDrinkSpellVisualTimer
Definition Player.hpp:833
uint64_t getDuelArbiter() const
Definition Player.cpp:765
virtual bool isClassMage() const
Definition Player.cpp:2762
void removeTempItemEnchantsOnArena()
Definition Player.cpp:6939
SpellSet m_shapeshiftSpells
Definition Player.hpp:970
void setEnteringToWorld()
Definition Player.cpp:3552
SkillMap m_skills
Definition Player.hpp:979
bool loadFromDB(uint32_t guid)
Definition Player.cpp:14525
void setRestState(uint8_t state)
Definition Player.cpp:848
void addTalentPoints(uint32_t talentPoints, bool forBothSpecs=true)
Definition Player.cpp:6037
std::optional< uint8_t > findFreeActivePetSlot() const
Definition Player.cpp:12349
bool m_disableAppearing
Definition Player.hpp:1101
bool m_isMoving
Definition Player.hpp:618
uint32_t checkDamageLimits(uint32_t damage, uint32_t spellId)
Definition Player.cpp:13289
float getBlockPercentage() const
Definition Player.cpp:1081
bool hasSkillLine(uint16_t skillLine, bool strict=false) const
Definition Player.cpp:4912
uint32_t getMountVehicleId() const
Definition Player.cpp:1516
void modExpertise(int32_t value)
Definition Player.cpp:1093
uint32_t getGuildLevel() const
Definition Player.cpp:816
uint8_t m_duelStatus
Definition Player.hpp:1727
void setVendorBuybackSlot(uint8_t slot, uint64_t guid)
Definition Player.cpp:958
Player * getDuelPlayer() const
Definition Player.cpp:11874
uint16_t getSkillInfoId(uint32_t index, uint8_t offset) const
Definition Player.cpp:1014
uint32_t m_classicMaxLevel
Definition Player.hpp:733
void removePetCache(uint8_t petId)
Definition Player.cpp:12310
void _addCooldown(uint32_t type, uint32_t mis, uint32_t time, uint32_t SpellId, uint32_t ItemId)
Definition Player.cpp:4601
void setDuelTeam(uint32_t team)
Definition Player.cpp:871
uint64_t getComboPointTarget() const
Definition Player.cpp:5356
uint32_t getTrackResource() const
Definition Player.cpp:1078
uint16_t getSkillInfoCurrentValue(uint32_t index, uint8_t offset) const
Definition Player.cpp:1016
void sendEquipmentSetList()
Definition Player.cpp:9748
bool m_isCorpseCreationAllowed
Definition Player.hpp:1214
void addItemsToWorld()
Definition Player.cpp:16083
void removeQuestMob(uint32_t entry)
Definition Player.cpp:9009
bool isFriended(uint32_t guid) const
Definition Player.cpp:9211
void addSummonSpell(uint32_t entry, uint32_t spellId)
Definition Player.cpp:13969
uint32_t m_team
Definition Player.hpp:739
void modModTargetPhysicalResistance(int32_t value)
Definition Player.cpp:1223
void setChampioningFaction(uint32_t factionId)
Definition Player.cpp:11823
void setTalentPointsFromQuests(uint32_t talentPoints)
Definition Player.cpp:6147
void setDualWield2H(bool enable)
Definition Player.cpp:4266
std::set< uint32_t > quest_spells
Definition Player.hpp:1529
uint32_t getModTargetPhysicalResistance() const
Definition Player.cpp:1221
void requestDuel(Player *target)
Definition Player.cpp:11875
bool m_isQueuedForRbg
Definition Player.hpp:1461
void updatePvPArea()
Definition Player.cpp:8231
void sendPetTameFailure(uint8_t result) const
Definition Player.cpp:9628
float getDodgePercentage() const
Definition Player.cpp:1084
bool isInCity() const
Definition Player.cpp:1537
LocationVector getLastGroupPosition() const
Definition Player.cpp:7956
uint32_t getLifetimeHonorableKills() const
Definition Player.cpp:1263
void updateChances()
Definition Player.cpp:15401
uint32_t getTrackCreature() const
Definition Player.cpp:1075
uint64_t m_currentLoot
Definition Player.hpp:1649
uint64_t m_resurrecter
Definition Player.hpp:1216
bool m_canDualWield2H
Definition Player.hpp:972
uint32_t getExaltedCount()
Definition Player.cpp:11747
void handleAuraInterruptForMovementFlags(MovementInfo const &movement_info)
Definition Player.cpp:1519
bool isOnVehicle() const
Definition Player.cpp:1515
uint8_t getBankSlots() const
Definition Player.cpp:844
std::list< std::unique_ptr< Item > > m_GarbageItems
Definition Player.hpp:1151
void loadIgnoreList()
Definition Player.cpp:9105
uint32_t m_pvpTimer
Definition Player.hpp:1412
uint32_t m_inviteArenaTeamId
Definition Player.hpp:1359
bool m_isQueuedForBg
Definition Player.hpp:1458
uint32_t m_bgQueueType
Definition Player.hpp:1464
void sendMoveSetSpeedPaket(UnitSpeedType speed_type, float speed)
Definition Player.cpp:1385
PetCache const * getPetCache(uint8_t petId) const
Definition Player.cpp:12276
void setResurrectPosition(LocationVector position)
Definition Player.cpp:7779
void sendFriendStatus(bool comesOnline)
Definition Player.cpp:9222
uint32_t getPlayerFieldBytes() const
Definition Player.cpp:1226
void addGlobalCooldown(SpellInfo const *spellInfo, Spell *castingSpell, const bool sendPacket=false)
Definition Player.cpp:4378
void initialiseReputation()
Definition Player.cpp:11803
void setMountSpellId(uint32_t id)
Definition Player.cpp:1513
void addCalculatedRestXp(uint32_t seconds)
Definition Player.cpp:12224
void setBankSlotItemGuid(uint8_t slot, uint64_t guid)
Definition Player.cpp:952
void addQuestMob(uint32_t entry)
Definition Player.cpp:8997
uint32_t getHonorToday() const
Definition Player.cpp:8190
int32_t getCorpseInstanceId() const
Definition Player.cpp:7430
Battleground * m_bg
Definition Player.hpp:1455
BGEntryData m_bgEntryData
Definition Player.hpp:1261
static void initVisibleUpdateBits()
Definition Player.cpp:3316
void unsetBanned()
Definition Player.cpp:2341
Creature * getCreatureWhenICanInteract(WoWGuid const &guid, uint32_t npcflagmask)
Definition Player.cpp:16884
uint32_t m_timeSyncCounter
Definition Player.hpp:1922
static void changeLooks(uint64_t guid, uint8_t gender, uint8_t skin, uint8_t face, uint8_t hairStyle, uint8_t hairColor, uint8_t facialHair)
Definition Player.cpp:2887
bool m_beingPushed
Definition Player.hpp:2175
void _updateSkillFieldOnValueChange(const PlayerSkillFieldPosition fieldPosition, uint16_t skillStep, uint16_t currentValue, uint16_t maxValue)
Definition Player.cpp:5783
uint16_t getSkillInfoBonusTemporary(uint32_t index, uint8_t offset) const
Definition Player.cpp:1018
void saveAuras(std::stringstream &)
Definition Player.cpp:16563
float getManaRegeneration() const
Definition Player.cpp:1142
void addHonor(uint32_t honorPoints, bool sendUpdate)
Definition Player.cpp:8133
std::string afkReason
Definition Player.hpp:1119
std::mutex m_mutexChannel
Definition Player.hpp:1337
uint32_t m_nextSave
Definition Player.hpp:2040
uint32_t getBlockDamageReduction()
Definition Player.cpp:13324
uint32_t calcTalentResetCost(uint32_t resetnum) const
Definition Player.cpp:6321
WDB::Structures::ChrRacesEntry const * getDbcRaceEntry()
Definition Player.cpp:2636
void setFallDisabledUntil(time_t time)
Definition Player.cpp:2048
uint8_t getDuelStatus() const
Definition Player.cpp:12126
void handleSobering()
Definition Player.cpp:11865
void setInitialDisplayIds(uint8_t gender, uint8_t race)
Definition Player.cpp:2645
void setRoles(uint8_t role)
Definition Player.cpp:8580
void removePvpFlag() override
Definition Player.cpp:9806
void setPlayerInfoIfNeeded()
Definition Player.cpp:9492
std::map< uint32_t, WeaponModifier > m_damageDone
Definition Player.hpp:2093
void sendInitialLogonPackets()
Definition Player.cpp:3032
void setBattleground(Battleground *bg)
Definition Player.cpp:8547
uint32_t getInitialFactionId()
Definition Player.cpp:11812
float getParryPercentage() const
Definition Player.cpp:1087
void sendEmptyPetSpellList()
Definition Player.cpp:9767
uint64_t getCoinage() const
Definition Player.cpp:1184
void updateInrangeSetsBasedOnReputation()
Definition Player.cpp:11610
uint32_t getKillsLifetime() const
Definition Player.cpp:8210
void updatePotionCooldown()
Definition Player.cpp:4532
LevelInfo const * m_levelInfo
Definition Player.hpp:725
void sendPlayObjectSoundPacket(uint64_t objectGuid, uint32_t soundId)
Definition Player.cpp:9661
uint32_t m_timeSyncServer
Definition Player.hpp:1925
void disableSummoning(bool disable)
Definition Player.cpp:2325
int32_t m_rapModPct
Definition Player.hpp:2182
uint64_t getAreaSpiritHealerGuid() const
Definition Player.cpp:7781
void sendPoiById(uint32_t id)
Definition Player.cpp:9640
Unit * getUnitOwner() override
Definition Player.cpp:2790
void loadFriendList()
Definition Player.cpp:9072
uint32_t getResistanceBuffModNegative(uint8_t type) const
Definition Player.cpp:1197
uint32_t getFreePrimaryProfessionPoints() const
Definition Player.cpp:1043
InstanceTimeMap m_instanceResetTimes
Definition Player.hpp:2153
void setDrunkValue(uint8_t value)
Definition Player.cpp:859
void addQuestKill(uint32_t questId, uint8_t reqId, uint32_t delay=0)
Definition Player.cpp:9015
bool m_sendOnlyRaidgroup
Definition Player.hpp:1320
uint8_t retRoles() const
Definition Player.cpp:8581
bool m_FirstCastAutoRepeat
Definition Player.hpp:961
void removeItemsFromWorld()
Definition Player.cpp:16112
bool m_tutorialsDirty
Definition Player.hpp:1026
uint8_t getStableSlotCount() const
Definition Player.cpp:12663
bool hasQuestInFinishedDailies(uint32_t questId) const
Definition Player.cpp:8887
void createCorpse()
Definition Player.cpp:7445
void sendSetProficiencyPacket(uint8_t itemClass, uint32_t proficiency)
Definition Player.cpp:9601
void addArenaPoints(uint32_t arenaPoints, bool sendUpdate)
Definition Player.cpp:8092
std::set< uint64_t > m_visibleObjects
Definition Player.hpp:803
uint16_t getSkillInfoStep(uint32_t index, uint8_t offset) const
Definition Player.cpp:1015
void setSkillInfoCurrentValue(uint32_t index, uint8_t offset, uint16_t current)
Definition Player.cpp:1023
uint32_t weaponProficiency
Definition Player.hpp:982
void loadBoundInstances()
Definition Player.cpp:12729
uint32_t getPlayerBytes3() const
Definition Player.cpp:852
void setGuildLevel(uint32_t guildLevel)
Definition Player.cpp:817
void sendSpellCooldownPacket(SpellInfo const *spellInfo, const uint32_t duration, const bool isGcd)
Definition Player.cpp:4409
float getManaRegenerationWhileCasting() const
Definition Player.cpp:1145
UpdateManager m_updateMgr
Definition Player.hpp:783
uint32_t m_healthFromItems
Definition Player.hpp:2219
void setAllowedToCreateCorpse(bool allowed)
Definition Player.cpp:7435
void modifyBonuses(uint32_t type, int32_t val, bool apply)
Definition Player.cpp:16317
void sendPvpCredit(uint32_t honor, uint64_t victimGuid, uint32_t victimRank)
Definition Player.cpp:9885
void removeSummonSpell(uint32_t entry, uint32_t spellId)
Definition Player.cpp:13997
void resetPvPTimer()
Definition Player.cpp:8215
void setSelectedGo(uint64_t guid)
Definition Player.cpp:2352
void acceptQuest(uint64_t guid, uint32_t quest_id)
Definition Player.cpp:8642
bool hasQuestSpell(uint32_t spellId)
Definition Player.cpp:8982
void removeAllChannels()
Definition Player.cpp:8043
void setProfessionSkillLine(uint32_t index, uint32_t value)
Definition Player.cpp:1027
void cleanupAfterTaxiFlight()
Definition Player.cpp:10693
void sendAuctionCommandResult(Auction *auction, uint32_t Action, uint32_t ErrorCode, uint32_t bidError=0)
Definition Player.cpp:6476
void removeAllSkills()
Definition Player.cpp:5156
void setFactionAtWar(uint32_t faction, bool set)
Definition Player.cpp:11558
void setGlyph(uint16_t slot, uint32_t glyph)
Definition Player.cpp:1310
void learnSkillSpells(uint16_t skillLine, uint16_t currentValue)
Definition Player.cpp:4976
Charter const * getCharter(uint8_t charterType)
Definition Player.cpp:7836
int8_t getSubGroupSlot() const
Definition Player.cpp:7898
bool isOnGMTargetList(uint32_t guid) const
Definition Player.cpp:2411
void setKnownCurrencies(uint64_t currencies)
Definition Player.cpp:990
void toggleAfk()
Definition Player.cpp:2854
virtual bool isClassPriest() const
Definition Player.cpp:2764
void sendReportToGmMessage(std::string playerName, std::string damageLog)
Definition Player.cpp:6537
bool hasAreaExplored(WDB::Structures::AreaTableEntry const *)
Definition Player.cpp:2165
void setSpellCritPercentage(uint8_t school, float value)
Definition Player.cpp:1111
void setTransferStatus(uint8_t status)
Definition Player.cpp:1889
bool isSanctuaryFlagSet() const override
Definition Player.cpp:9852
std::optional< uint8_t > findFreeStablePetSlot() const
Definition Player.cpp:12363
bool isVisibleObject(uint64_t guid)
Definition Player.cpp:3599
void sendLooter(Creature *creature)
Definition Player.cpp:11154
uint32_t getExploredZone(uint32_t idx) const
Definition Player.cpp:1122
std::string getBanReason() const
Definition Player.cpp:2342
void addInstanceEnterTime(uint32_t instanceId, time_t enterTime)
Definition Player.cpp:13128
bool hasTimedQuestInQuestSlot() const
Definition Player.cpp:8898
float getModDamageDonePct(uint8_t shool) const
Definition Player.cpp:1209
void setPlayerGender(uint8_t gender)
Definition Player.cpp:856
QuestLogEntry * getQuestLogBySlotId(uint32_t slotId) const
Definition Player.cpp:8869
void setModDamageDonePct(float damagePct, uint8_t shool)
Definition Player.cpp:1210
void sendLootUpdate(Object *object)
Definition Player.cpp:11129
void removeHonor(uint32_t honorPoints, bool sendUpdate)
Definition Player.cpp:8149
utf8_string getName() const
Definition Player.cpp:2639
uint32_t getQuestLogEntryForSlot(uint8_t slot) const
Definition Player.cpp:877
uint16_t m_spellAreaUpdateTimer
Definition Player.hpp:1913
void updateAttackSpeed()
Definition Player.cpp:15504
void unEquipOffHandIfRequired()
Definition Player.cpp:6576
std::set< Channel * > m_channels
Definition Player.hpp:1336
void updateRageRegeneration(bool initialUpdate=false)
uint32_t m_timeLogoff
Definition Player.hpp:745
InstanceSaved * getInstanceSave(uint32_t mapId, bool isRaid)
Definition Player.cpp:12819
void setResurrectMana(uint32_t mana)
Definition Player.cpp:7776
void initialiseNoseLevel()
Definition Player.cpp:1636
CorpseData m_corpseData
Definition Player.hpp:1212
uint32_t m_flatStatModNeg[5]
Definition Player.hpp:2071
void modModDamageDoneNegative(uint16_t school, int32_t value)
Definition Player.cpp:1207
bool isTransferPending() const
Definition Player.cpp:1891
void onKillUnitReputation(Unit *unit, bool innerLoop)
Definition Player.cpp:11633
void applyFeralAttackPower(bool apply, Item *item=NULL)
Definition Player.cpp:13337
void setPvpRank(uint8_t rank)
Definition Player.cpp:862
bool isTeamHorde() const
Definition Player.cpp:2787
uint32_t getGroupInviterId() const
Definition Player.cpp:7882
void setVisibleItemEnchantment(uint32_t slot, uint8_t pos, uint32_t enchantment)
Definition Player.cpp:941
std::array< ArenaTeam *, NUM_ARENA_TEAM_TYPES > m_arenaTeams
Definition Player.hpp:1357
void setPendingBind(uint32_t instanceId, uint32_t bindTimer)
Definition Player.cpp:12921
void addQuestSpell(uint32_t spellId)
Definition Player.cpp:8979
SummonData m_summonData
Definition Player.hpp:1117
void addArmorProficiency(uint32_t proficiency)
Definition Player.cpp:5228
void copyAndSendDelayedPacket(WorldPacket *data)
Definition Player.cpp:3550
bool loadSkills(QueryResult *result)
Definition Player.cpp:3872
void setBgTeam(uint32_t team)
Definition Player.cpp:2777
void setPlayerFieldBytes(uint32_t bytes)
Definition Player.cpp:1227
void setMeleeCritPercentage(float value)
Definition Player.cpp:1101
bool saveReputations(bool newCharacter, QueryBuffer *buf)
Definition Player.cpp:13356
bool m_lootableOnCorpse
Definition Player.hpp:1650
uint32_t getProfessionSkillLine(uint32_t index) const
Definition Player.cpp:1020
uint32_t m_tutorials[8]
Definition Player.hpp:1025
uint32_t getVisibleItemEnchantment(uint32_t slot, uint8_t pos) const
Definition Player.cpp:940
void sendResetInstanceFailed(uint32_t reason, uint32_t MapId)
Definition Player.cpp:13094
void removeSanctuaryFlag() override
Definition Player.cpp:9874
void kickFromServer(uint32_t delay=0)
Definition Player.cpp:2354
uint8_t getFreeQuestSlot() const
Definition Player.cpp:8850
void setPctReputationMod(int32_t value)
Definition Player.cpp:11821
void addSkillLine(uint16_t skillLine, uint16_t currentValue, uint16_t maxValue, bool noSpellLearning=false, bool initializeProfession=false)
Definition Player.cpp:4760
float getDefenseChance(uint32_t opLevel)
Definition Player.cpp:15334
void sendMessageToSet(WorldPacket *data, bool sendToSelf, bool sendToOwnTeam=false) override
Definition Player.cpp:3192
void setFreePrimaryProfessionPoints(uint32_t points)
Definition Player.cpp:1052
void _updateSkillBonusFields(const PlayerSkillFieldPosition fieldPosition, uint16_t tempBonus, uint16_t permBonus)
Definition Player.cpp:5800
uint32_t m_flyingAura
Definition Player.hpp:2177
uint8_t m_battlegroundLastPetId
Definition Player.hpp:1805
void sendEquipmentSetSaved(uint32_t setId, uint32_t setGuid)
Definition Player.cpp:9757
void resetAllCooldowns()
Definition Player.cpp:4454
Object * getSummonedObject() const
Definition Player.cpp:12704
void sendPreventSchoolCast(uint32_t spellSchool, uint32_t timeMs)
Definition Player.cpp:4014
void modModDamageDonePositive(uint16_t school, int32_t value)
Definition Player.cpp:1203
bool compressAndSendUpdateBuffer(uint32_t size, const uint8_t *update_buffer)
Definition Player.cpp:3242
void setFullHealthMana()
Definition Player.cpp:7784
void addQuestIdToFinishedDailies(uint32_t questId)
Definition Player.cpp:8877
bool hasAnyQuestInQuestSlot() const
Definition Player.cpp:8833
void die(Unit *unitAttacker, uint32_t damage, uint32_t spellId) override
Definition Player.cpp:7258
void removeAuraVision(uint8_t auraVision)
void setSkillInfoBonusPermanent(uint32_t index, uint8_t offset, uint16_t bonus)
Definition Player.cpp:1026
void smsg_TalentsInfo(bool SendPetTalents)
Definition Player.cpp:6152
void addGarbageItem(std::unique_ptr< Item > item)
Definition Player.cpp:6968
void applyForcedReaction(uint32_t faction_id, Standing rank, bool apply)
Definition Player.cpp:11544
uint32_t m_resurrectHealth
Definition Player.hpp:1217
uint32_t m_teleportState
Definition Player.hpp:631
void setAFKReason(std::string reason)
Definition Player.cpp:2396
void resetInstances(uint8_t method, bool isRaid)
Definition Player.cpp:13046
void sendFriendLists(uint32_t flags)
Definition Player.cpp:9243
uint32_t getGlyph(uint16_t slot) const
Definition Player.cpp:1309
uint32_t m_honorRolloverTime
Definition Player.hpp:1385
uint8_t getPlayerFieldBytesMiscFlag() const
Definition Player.cpp:1229
void _savePlayerCooldowns(QueryBuffer *buf)
Definition Player.cpp:4665
void removeArmorProficiency(uint32_t proficiency)
Definition Player.cpp:5233
bool loadReputations(QueryResult *result)
Definition Player.cpp:3891
void resendSpeed()
Definition Player.cpp:1501
void removeFfaPvpFlag() override
Definition Player.cpp:9840
uint32_t getModTargetResistance() const
Definition Player.cpp:1217
void setTrackResource(uint32_t id)
Definition Player.cpp:1079
void forceZoneUpdate()
Definition Player.cpp:2151
uint64_t getPackSlotItemGuid(uint8_t slot) const
Definition Player.cpp:948
void _loadPet(QueryResult *result)
Definition Player.cpp:14017
void setBuybackPriceSlot(uint8_t slot, uint32_t price)
Definition Player.cpp:1243
void ejectFromInstance()
Definition Player.cpp:2301
void learnInitialSkills()
Definition Player.cpp:4956
std::mutex m_mutexFriendList
Definition Player.hpp:1560
FactionReputation * m_reputationByListId[128]
Definition Player.hpp:1692
void setBankSlots(uint8_t slots)
Definition Player.cpp:845
void setArenaTeam(uint8_t type, ArenaTeam *arenaTeam)
Definition Player.cpp:8063
float getSkillUpChance(uint16_t id)
Definition Player.cpp:5191
void sendLoginVerifyWorldPacket(uint32_t mapId, float posX, float posY, float posZ, float orientation)
Definition Player.cpp:9699
void resetHolyPowerTimer()
Definition Player.cpp:3838
uint8_t getEnabledActionBars() const
Definition Player.cpp:1234
PlayerTeam getTeam() const
Definition Player.cpp:2774
uint8_t getHairStyle() const
Definition Player.cpp:830
PlayerCheat m_cheats
Definition Player.hpp:1090
uint32_t m_restAmount
Definition Player.hpp:1751
void removeFromIgnoreList(uint32_t guid)
Definition Player.cpp:9341
LocationVector m_lastGroupPosition
Definition Player.hpp:1322
PetCache * getModifiablePetCache(uint8_t petId) const
Definition Player.cpp:12285
Group * getGroup()
Definition Player.cpp:7887
void saveInstanceTimeRestrictions()
Definition Player.cpp:13134
CachedCharacterInfo * m_playerInfo
Definition Player.hpp:747
int8_t getComboPoints() const
Definition Player.cpp:5361
bool isLootableOnCorpse() const
Definition Player.cpp:11309
uint8_t getLastBattlegroundPetId() const
Definition Player.cpp:12658
void removeFromWorld()
Definition Player.cpp:712
uint32_t m_resurrectMapId
Definition Player.hpp:1220
uint16_t getGroupStatus()
Definition Player.cpp:7914
void setPlayerBytes(uint32_t bytes)
Definition Player.cpp:822
uint32_t m_bgTeam
Definition Player.hpp:740
bool m_disableSummoning
Definition Player.hpp:1102
PlayerCreateInfo const * m_playerCreateInfo
Definition Player.hpp:750
bool activateTaxiPathTo(std::vector< uint32_t > const &nodes, Creature *npc=nullptr, uint32_t spellid=0)
Definition Player.cpp:10513
virtual bool isClassHunter() const
Definition Player.cpp:2767
void eventTimedQuestExpire(uint32_t questId)
Definition Player.cpp:8907
void advanceSkillLine(uint16_t skillLine, uint16_t amount=1)
Definition Player.cpp:4713
uint8_t m_talentSpecsCount
Definition Player.hpp:1987
void setNoReagentCost(uint8_t index, uint32_t value)
Definition Player.cpp:1304
uint8_t getArenaFaction() const
Definition Player.cpp:865
uint32_t getGuildRank() const
Definition Player.cpp:812
void rolloverHonor()
Definition Player.cpp:8178
bool hasSpellGlobalCooldown(SpellInfo const *spellInfo)
Definition Player.cpp:4330
void eventTalentHearthOfWildChange(bool apply)
Definition Player.cpp:13583
virtual bool isClassShaman() const
Definition Player.cpp:2766
UpdateManager & getUpdateMgr()
Definition Player.cpp:3554
void areaExploredQuestEvent(uint32_t questId)
Definition Player.cpp:8940
uint32_t m_pendingBindId
Definition Player.hpp:2156
void setInitialPlayerProfessions()
Definition Player.cpp:5201
void setFfaPvpFlag() override
Definition Player.cpp:9828
void setHasWonRbgToday(bool value)
Definition Player.cpp:8572
bool hasPvPTitle(RankTitles title)
Definition Player.cpp:8515
void sendSmsgInitialSpells()
Definition Player.cpp:3970
void setDuelStatus(uint8_t status)
Definition Player.cpp:12125
bool canTrainAt(Trainer const *trainer)
Definition Player.cpp:10258
void setSkillInfoStep(uint32_t index, uint8_t offset, uint16_t step)
Definition Player.cpp:1022
std::map< uint8_t, uint8_t > m_cachedPetSlots
Definition Player.hpp:1803
uint32_t getGuildTimestamp() const
Definition Player.cpp:873
void modModTargetResistance(int32_t value)
Definition Player.cpp:1219
void loadFieldsFromString(const char *string, uint16_t firstField, uint32_t fieldsNum)
Definition Player.cpp:13174
void modCoinage(int64_t coinage)
Definition Player.cpp:1187
bool saveDeletedSpells(bool newCharacter, QueryBuffer *buf)
Definition Player.cpp:13450
uint8_t getPlayerGender() const
Definition Player.cpp:855
void sendSavedInstances()
Definition Player.cpp:12977
void setFarsightGuid(uint64_t farsightGuid)
Definition Player.cpp:976
void setDodgePercentage(float value)
Definition Player.cpp:1085
bool m_blinked
Definition Player.hpp:2174
uint32_t m_itemUpdateTimer
Definition Player.hpp:1916
bool isInArenaTeam(uint8_t type) const
Definition Player.cpp:8072
void setDuelState(uint8_t state)
Definition Player.cpp:12128
bool isHostileBasedOnReputation(WDB::Structures::FactionEntry const *factionEntry)
Definition Player.cpp:11591
std::map< uint32_t, Standing > m_forcedReactions
Definition Player.hpp:2228
void incrementKills(uint32_t count=0)
Definition Player.cpp:8196
void setHairStyle(uint8_t style)
Definition Player.cpp:831
WDB::Structures::ChrClassesEntry const * m_dbcClass
Definition Player.hpp:728
uint8_t m_talentActiveSpec
Definition Player.hpp:1988
void setPlayerBytes2(uint32_t bytes2)
Definition Player.cpp:839
SpellSet m_deletedSpellSet
Definition Player.hpp:969
std::vector< uint32_t > m_gmPlayerTargetList
Definition Player.hpp:1121
uint16_t m_partyUpdateTimer
Definition Player.hpp:1915
void setMover(Unit *target)
Definition Player.cpp:10283
void _loadQuestLogEntry(QueryResult *result)
Definition Player.cpp:15297
uint32_t getVisibleItemEntry(uint32_t slot) const
Definition Player.cpp:921
void cancelTrade(bool sendToSelfAlso, bool silently=false)
Definition Player.cpp:6511
void setInviteArenaTeamId(uint32_t id)
Definition Player.cpp:8128
void displayDataStateList()
Definition Player.cpp:13269
void setPackSlotItemGuid(uint8_t slot, uint64_t guid)
Definition Player.cpp:949
uint8_t getRaidDifficulty()
Definition Player.cpp:7251
void setBGEntryPoint(float x, float y, float z, float o, uint32_t mapId, int32_t instanceId)
Definition Player.cpp:7822
void setQuestSharerDbId(uint32_t id)
Definition Player.cpp:8923
uint8_t m_raidDifficulty
Definition Player.hpp:1169
void clearCooldownsOnLine(uint32_t skillLine, uint32_t calledFrom)
Definition Player.cpp:16141
void updateChanceFields()
Definition Player.cpp:15496
void setBlockPercentage(float value)
Definition Player.cpp:1082
uint64_t getBankBagSlotItemGuid(uint8_t slot) const
Definition Player.cpp:954
bool exitInstance()
Definition Player.cpp:2310
bool m_reincarnation
Definition Player.hpp:2091
uint32_t getNoReagentCost(uint8_t index) const
Definition Player.cpp:1303
void stopPvPTimer()
Definition Player.cpp:8216
void setShieldBlock(uint32_t value)
Definition Player.cpp:1114
void testDuelBoundary()
Definition Player.cpp:11914
void setDungeonDifficulty(uint8_t diff)
Definition Player.cpp:7236
virtual bool isClassWarrior() const
Definition Player.cpp:2769
bool cooldownCanCast(ItemProperties const *itemProp, uint32_t spellIndex)
Definition Player.cpp:4502
void regenerateHealth(bool inCombat)
Definition Player.cpp:15932
std::mutex m_lockGMTargetList
Definition Player.hpp:1122
uint32_t getInviteArenaTeamId() const
Definition Player.cpp:8129
void clearComboPoints()
Definition Player.cpp:5420
float getRuneRegen(uint8_t rune) const
Definition Player.cpp:1168
void applyItemMods(Item *item, int16_t slot, bool apply, bool justBrokedown=false, bool skipStatApply=false)
Definition Player.cpp:6972
uint32_t _fields[getSizeOfStructure(WoWPlayer)]
Definition Player.hpp:2225
void sendTaxiNodeStatusMultiple()
Definition Player.cpp:10748
bool hasItem(uint32_t itemId, uint32_t amount=1, bool checkBankAlso=false) const
Definition Player.cpp:6641
void eventAttackStop()
Definition Player.cpp:13776
void handleSpellLoot(uint32_t itemId)
Definition Player.cpp:13255
uint32_t m_killsToday
Definition Player.hpp:1392
void sendAreaTriggerMessage(const char *message,...)
Definition Player.cpp:6563
void addGroupUpdateFlag(uint32_t flag)
Definition Player.cpp:7908
uint8_t getDuelState() const
Definition Player.cpp:12129
void setModHealingDone(uint32_t value)
Definition Player.cpp:1214
void setGroupUpdateFlags(uint32_t flags)
Definition Player.cpp:7902
uint32_t m_groupUpdateFlags
Definition Player.hpp:1324
void removeArenaPoints(uint32_t arenaPoints, bool sendUpdate)
Definition Player.cpp:8104
bool hasDeletedSpell(uint32_t spellId) const
Definition Player.cpp:3930
void continueTaxiFlight() const
Definition Player.cpp:10700
uint32_t m_resistanceModPctNeg[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2056
void sendCastFailedPacket(uint32_t spellId, uint8_t errorMessage, uint8_t multiCast, uint32_t extra1, uint32_t extra2=0)
Definition Player.cpp:9714
void setExpertise(uint32_t value)
Definition Player.cpp:1092
uint32_t m_mountSpellId
Definition Player.hpp:624
Item * storeItem(LootItem const *lootItem)
Definition Player.cpp:11221
void setRaidDifficulty(uint8_t diff)
Definition Player.cpp:7246
uint32_t getGroupUpdateFlags() const
Definition Player.cpp:7900
void resetTalents()
Definition Player.cpp:5966
std::mutex m_mutexFriendedBy
Definition Player.hpp:1563
void updateRestState()
Definition Player.cpp:12262
SpellSet const & getShapeshiftSpells() const
Definition Player.cpp:4080
void sendLoot(uint64_t guid, uint8_t loot_type, uint32_t mapId)
Definition Player.cpp:10791
void setPvpFlag() override
Definition Player.cpp:9790
void sendMirrorTimer(MirrorTimerTypes mirrorType, uint32_t max, uint32_t current, int32_t regen)
Definition Player.cpp:16157
uint32_t getArmorProficiency() const
Definition Player.cpp:5223
void setLoginPosition()
Definition Player.cpp:9461
void setAreaSpiritHealerGuid(uint64_t guid)
Definition Player.cpp:7782
uint32_t getBindMapId() const
Definition Player.cpp:7817
void setAuraVision(uint8_t auraVision)
bool isAppearingDisabled() const
Definition Player.cpp:2328
void addSpell(uint32_t spellId, uint16_t fromSkill=0)
Definition Player.cpp:3935
Player * getTradeTarget() const
Definition Player.cpp:6501
uint64_t getVendorBuybackSlot(uint8_t slot) const
Definition Player.cpp:957
float m_offhandDmgMod
Definition Player.hpp:1937
~Player()
Definition Player.cpp:258
void applyPlayerRestState(bool apply)
Definition Player.cpp:12245
uint32_t getTalentPointsFromQuests() const
Definition Player.cpp:6142
void initialiseCharters()
Definition Player.cpp:7855
void setOffHandExpertise(uint32_t value)
Definition Player.cpp:1096
void clearQuest(uint32_t questId)
Definition Player.cpp:8945
uint32_t getWatchedFaction() const
Definition Player.cpp:1138
void setResurrect()
Definition Player.cpp:7795
void setLifetimeHonorableKills(uint32_t kills)
Definition Player.cpp:1264
void handleKnockback(Object *caster, float horizontal, float vertical) override
Definition Player.cpp:1724
void onWorldPortAck()
Definition Player.cpp:1989
void loadInstanceTimeRestrictions()
Definition Player.cpp:13106
uint32_t m_underwaterTime
Definition Player.hpp:583
void setSkillInfoBonusTemporary(uint32_t index, uint8_t offset, uint16_t bonus)
Definition Player.cpp:1025
uint8_t m_isResting
Definition Player.hpp:1749
uint32_t getOffHandExpertise() const
Definition Player.cpp:1095
uint8_t getFacialFeatures() const
Definition Player.cpp:841
virtual bool isClassWarlock() const
Definition Player.cpp:2768
void removeQuestSpell(uint32_t spellId)
Definition Player.cpp:8991
uint8_t m_transferStatus
Definition Player.hpp:630
void updateChannels()
Definition Player.cpp:7978
bool isSendOnlyRaidgroupSet() const
Definition Player.cpp:7953
bool isInDisallowedMountForm() const
Definition Player.cpp:4125
bool loadDeletedSpells(QueryResult *result)
Definition Player.cpp:13427
bool hasPlayerFlags(uint32_t flags) const
Definition Player.cpp:786
void setUpdateBits(UpdateMask *updateMask, Player *target) const
Definition Player.cpp:3572
void setModDamageDonePositive(uint16_t school, uint32_t value)
Definition Player.cpp:1202
uint8_t getRestState() const
Definition Player.cpp:847
void sendResetFailedNotify(uint32_t mapid)
Definition Player.cpp:9584
uint32_t m_flatResistanceModifierNeg[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2052
LocationVector getBindPosition() const
Definition Player.cpp:7816
time_t m_fallDisabledUntil
Definition Player.hpp:635
uint32_t m_queuedBgInstanceId
Definition Player.hpp:1459
void processPendingUpdates()
Definition Player.cpp:13578
uint32_t m_timeSyncTimer
Definition Player.hpp:1923
uint8_t getFreePetNumber()
Definition Player.cpp:12325
bool canUseFlyingMountHere()
Definition Player.cpp:4210
void setSanctuaryFlag() override
Definition Player.cpp:9863
void setInitialPlayerData()
Definition Player.cpp:3616
float getSpellCritFromSpell()
Definition Player.hpp:2035
void addPetCache(std::unique_ptr< PetCache > petCache, uint8_t index)
Definition Player.cpp:12304
bool hasSpell(uint32_t spellId) const
Definition Player.cpp:3925
uint8_t m_roles
Definition Player.hpp:1468
int8_t m_comboPoints
Definition Player.hpp:985
void setQueuedBgInstanceId(uint32_t id)
Definition Player.cpp:8557
void setResurrectInstanceId(uint32_t id)
Definition Player.cpp:7777
std::set< uint32_t > m_finishedQuests
Definition Player.hpp:1527
std::optional< uint8_t > getPetIdFromSlot(uint8_t slot) const
Definition Player.cpp:12335
void setLootableOnCorpse(bool lootable)
Definition Player.cpp:11310
uint32_t m_kickDelay
Definition Player.hpp:1108
void addQuestToFinished(uint32_t questId)
Definition Player.cpp:8927
void setOffHandCritPercentage(float value)
Definition Player.cpp:1108
AIInterface * m_aiInterfaceWaypoint
Definition Player.hpp:1094
void setCoinage(uint64_t coinage)
Definition Player.cpp:1185
void setGlyphSlot(uint16_t slot, uint32_t glyph)
Definition Player.cpp:1307
uint32_t m_healthFromSpell
Definition Player.hpp:2217
void modifySkillMaximum(uint16_t skillLine, uint16_t maxValue)
Definition Player.cpp:5022
std::map< uint32_t, std::set< uint32_t > > m_summonSpells
Definition Player.hpp:2163
void initTaxiNodesForLevel()
Definition Player.cpp:10780
bool hasOverlayUncovered(uint32_t overlayId)
Definition Player.cpp:2180
uint32_t getQuestSharerByDbId() const
Definition Player.cpp:8922
std::map< uint32_t, WeaponModifier > m_toCritChance
Definition Player.hpp:2094
bool removeSpell(uint32_t spellId, bool moveToDeleted)
Definition Player.cpp:3945
void sendNewDrunkStatePacket(uint32_t state, uint32_t itemId)
Definition Player.cpp:9596
void setGuildId(uint32_t guildId)
Definition Player.cpp:796
uint32_t getHonorless() const
Definition Player.cpp:8192
uint32_t m_talentPointsFromQuests
Definition Player.hpp:1011
uint32_t m_AttackMsgTimer
Definition Player.hpp:2208
void eventDismissPet()
Definition Player.cpp:12697
WDB::Structures::ChrRacesEntry const * m_dbcRace
Definition Player.hpp:727
void setSkinColor(uint8_t color)
Definition Player.cpp:825
std::set< uint32_t > * getSummonSpells(uint32_t spellId)
Definition Player.cpp:14008
InstancePlayerBind * getBoundInstance(uint32_t mapId, InstanceDifficulty::Difficulties difficulty, bool withExpired=false)
Definition Player.cpp:12803
virtual bool isClassMonk() const
Definition Player.cpp:2771
uint32_t m_underwaterLastDamage
Definition Player.hpp:586
uint32_t getPlayerBytes2() const
Definition Player.cpp:838
void onRemoveInRangeObject(Object *object) override
Definition Player.cpp:15780
virtual bool isClassDeathKnight() const
Definition Player.cpp:2763
void setArenaFaction(uint8_t faction)
Definition Player.cpp:866
GameObject * getSelectedGo() const
Definition Player.cpp:2344
void learnTalent(uint32_t talentId, uint32_t talentRank)
Definition Player.cpp:5815
BindData m_bindData
Definition Player.hpp:1243
uint32_t getQuestLogStateForSlot(uint8_t slot) const
Definition Player.cpp:884
void spawnCorpseBody()
Definition Player.cpp:7508
uint32_t getRestStateXp() const
Definition Player.cpp:1172
void calcExpertise()
Definition Player.cpp:13192
bool tryPutPetToSlot(uint8_t petId, uint8_t newSlot, bool sendErrors=true)
Definition Player.cpp:12380
void addComboPoints(uint64_t targetGuid, int8_t points)
Definition Player.cpp:5366
bool hasQuestFinished(uint32_t questId) const
Definition Player.cpp:8935
std::set< uint32_t > getFinishedDailies() const
Definition Player.cpp:8882
uint32_t m_mountVehicleId
Definition Player.hpp:625
uint16_t getSkillInfoBonusPermanent(uint32_t index, uint8_t offset) const
Definition Player.cpp:1019
void sendMeetingStoneSetQueuePacket(uint32_t dungeonId, uint8_t status)
Definition Player.cpp:9656
std::unique_ptr< ItemInterface > m_itemInterface
Definition Player.hpp:1148
void setIsQueuedForRbg(bool value)
Definition Player.cpp:8560
Standing const * getForcedReputationRank(WDB::Structures::FactionTemplateEntry const *factionTemplateEntry) const
Definition Player.cpp:11552
void addPlayerFieldBytesMiscFlag(uint8_t miscFlag)
Definition Player.cpp:1231
void updatePvPCurrencies()
Definition Player.cpp:8509
static void changeLanguage(uint64_t guid, uint8_t race)
Definition Player.cpp:2902
void addToIgnoreList(std::string name)
Definition Player.cpp:9303
void setServersideDrunkValue(uint16_t newDrunkValue, uint32_t itemId=0)
Definition Player.cpp:11829
float getBlockChance()
Definition Player.cpp:15383
uint32_t getInvitedByGuildId() const
Definition Player.cpp:7864
std::array< Charter *, NUM_CHARTER_TYPES > m_charters
Definition Player.hpp:1273
void applyItemProficienciesFromSpell(SpellInfo const *spellInfo, bool apply)
Definition Player.cpp:5253
bool isFactionAtWar(WDB::Structures::FactionEntry const *factionEntry) const
Definition Player.cpp:11577
void setSkillInfoMaxValue(uint32_t index, uint8_t offset, uint16_t max)
Definition Player.cpp:1024
uint64_t m_GMSelectedGO
Definition Player.hpp:1104
void setHasBgFlag(bool set)
Definition Player.cpp:8578
void sendGuildMotd()
Definition Player.cpp:9740
void sendStopMirrorTimerPacket(MirrorTimerTypes type)
Definition Player.cpp:9651
uint32_t m_statModPctPos[5]
Definition Player.hpp:2072
void resetTeam()
Definition Player.cpp:2781
void eventGroupFullUpdate()
Definition Player.cpp:7947
void setStableSlotCount(uint8_t count)
Definition Player.cpp:12662
uint32_t m_killsYesterday
Definition Player.hpp:1394
uint32_t getWeaponProficiency() const
Definition Player.cpp:5238
uint32_t m_championingFactionId
Definition Player.hpp:1694
void modModHealingDone(int32_t value)
Definition Player.cpp:1215
uint64_t getBankSlotItemGuid(uint8_t slot) const
Definition Player.cpp:951
void unsetCharter(uint8_t charterType)
Definition Player.cpp:7835
std::mutex m_mutextDailies
Definition Player.hpp:1523
void calcDeathDurabilityLoss(double percent)
Definition Player.cpp:7747
void addDeletedSpell(uint32_t spellId)
Definition Player.cpp:3940
void _addSpell(uint32_t spellId, uint16_t fromSkill=0, bool learningPreviousRanks=false, bool ignorePreviousRanks=false)
Definition Player.cpp:5431
uint32_t m_manaFromItems
Definition Player.hpp:2220
bool m_cannibalize
Definition Player.hpp:2095
uint32_t getMaxPersonalRating()
Definition Player.cpp:13148
uint32_t m_questSharer
Definition Player.hpp:1528
void sendTeleportAckPacket(LocationVector position)
Definition Player.cpp:1957
Player * getPlayerOwnerOrSelf() override
Definition Player.cpp:2838
void sendRaidGroupOnly(uint32_t timeInMs, uint32_t type)
Definition Player.cpp:9890
void setName(std::string name)
Definition Player.cpp:2640
uint64_t m_areaSpiritHealerGuid
Definition Player.hpp:1223
bool hasSpellWithAuraNameAndBasePoints(uint32_t auraName, uint32_t basePoints)
Definition Player.cpp:4555
uint32_t m_honorToday
Definition Player.hpp:1388
void eventSummonPet(Pet *summonPet)
Definition Player.cpp:12665
void sendLevelupInfoPacket(uint32_t level, uint32_t hp, uint32_t mana, uint32_t stat0, uint32_t stat1, uint32_t stat2, uint32_t stat3, uint32_t stat4)
Definition Player.cpp:9719
void setCreateBits(UpdateMask *updateMask, Player *target) const
Definition Player.cpp:3556
void setSendOnlyRaidgroup(bool set)
Definition Player.cpp:7954
bool canBuyAt(MySQLStructure::VendorRestrictions const *vendor)
Definition Player.cpp:10221
void setLastBattlegroundPetId(uint8_t petId)
Definition Player.cpp:12657
void sendDismountResultPacket(uint32_t result)
Definition Player.cpp:9709
void sendWorldStateUpdate(uint32_t worldState, uint32_t value)
Definition Player.cpp:10216
bool hasBgFlag() const
Definition Player.cpp:8577
void speedCheatDelay(uint32_t delay)
Definition Player.cpp:9369
bool isFfaPvpFlagSet() const override
Definition Player.cpp:9819
void sendSmsgInitialFactions()
Definition Player.cpp:11762
void endDuel(uint8_t condition)
Definition Player.cpp:11955
void addShapeShiftSpell(uint32_t spellId)
Definition Player.cpp:4061
void addPlayerFlags(uint32_t flags)
Definition Player.cpp:784
void eventExploration()
Definition Player.cpp:2200
uint32_t m_underwaterState
Definition Player.hpp:585
uint32_t subtractRestXp(uint32_t amount)
Definition Player.cpp:12206
void setVisibleItemFields(uint32_t slot, Item *item)
Definition Player.cpp:9895
uint32_t getPlayerFieldBytes2() const
void setFactionStanding(uint32_t faction, int32_t value)
Definition Player.cpp:11369
std::list< LoginAura > m_loginAuras
Definition Player.hpp:1964
std::array< std::unique_ptr< QuestLogEntry >, MAX_QUEST_LOG_SIZE > m_questlog
Definition Player.hpp:1521
virtual bool isClassRogue() const
Definition Player.cpp:2765
bool safeTeleport(uint32_t mapId, uint32_t instanceId, const LocationVector &vec)
Definition Player.cpp:1772
void setTutorialValueForId(uint8_t id, uint32_t value)
Definition Player.cpp:6341
LocationVector getBGEntryPosition() const
Definition Player.cpp:7829
PetCacheMap m_cachedPets
Definition Player.hpp:1801
void removeWeaponProficiency(uint32_t proficiency)
Definition Player.cpp:5248
void setCurrencyTokenSlotItemGuid(uint8_t slot, uint64_t guid)
Definition Player.cpp:972
void sendAvailSpells(WDB::Structures::SpellShapeshiftFormEntry const *shapeshiftFormEntry, bool active)
Definition Player.cpp:4085
int m_hearthOfWildPct
Definition Player.hpp:1962
std::set< uint32_t > quest_mobs
Definition Player.hpp:1530
void sendItemPushResultPacket(bool created, bool recieved, bool sendtoset, uint8_t destbagslot, uint32_t destslot, uint32_t count, uint32_t entry, uint32_t suffix, uint32_t randomprop, uint32_t stack)
Definition Player.cpp:9724
uint32_t * getPlayedTime()
Definition Player.cpp:2883
uint8_t getFace() const
Definition Player.cpp:827
std::vector< SocialFriends > m_socialIFriends
Definition Player.hpp:1559
uint32_t getTalentResetsCount() const
Definition Player.cpp:6318
bool m_resetTalents
Definition Player.hpp:1013
void applyLevelInfo(uint32_t newLevel)
Definition Player.cpp:2669
void removePlayerFieldBytesMiscFlag(uint8_t miscFlag)
Definition Player.cpp:1232
void logIntoBattleground()
Definition Player.cpp:9402
void toggleDnd()
Definition Player.cpp:2875
bool hasWonRbgToday() const
Definition Player.cpp:8571
bool addNewFaction(WDB::Structures::FactionEntry const *factionEntry, int32_t standing, bool base)
Definition Player.cpp:11709
void sendTotemCreatedPacket(uint8_t slot, uint64_t guid, uint32_t duration, uint32_t spellId)
Definition Player.cpp:9623
void updateSkillMaximumValues()
Definition Player.cpp:5168
uint16_t getSkillInfoMaxValue(uint32_t index, uint8_t offset) const
Definition Player.cpp:1017
PetCacheMap const & getPetCacheMap() const
Definition Player.cpp:12294
void removeFromGMTargetList(uint32_t guid)
Definition Player.cpp:2405
uint32_t getShieldBlock() const
Definition Player.cpp:1113
uint8_t getTransferStatus() const
Definition Player.cpp:1890
void addSpellCooldown(SpellInfo const *spellInfo, Item const *itemCaster, Spell *castingSpell=nullptr, int32_t cooldownTime=0)
Definition Player.cpp:4347
InstanceDifficulty::Difficulties getDifficulty(bool isRaid) const
Definition Player.hpp:1159
bool hasSpellOnCooldown(SpellInfo const *spellInfo)
Definition Player.cpp:4298
void setGuildAndGroupInfo()
Definition Player.cpp:9517
void setRuneRegen(uint8_t rune, float regen)
Definition Player.cpp:1169
void setInitialTalentPoints(bool talentsResetted=false)
Definition Player.cpp:6056
void setExploredZone(uint32_t idx, uint32_t data)
Definition Player.cpp:1129
std::string m_banreason
Definition Player.hpp:1107
bool canSignCharter(Charter const *charter, Player *requester)
Definition Player.cpp:7838
time_t getFallDisabledUntil() const
Definition Player.cpp:2047
bool isAlreadyInvitedToGroup() const
Definition Player.cpp:7883
uint32_t m_honorYesterday
Definition Player.hpp:1389
float getDodgeChance()
Definition Player.cpp:15343
uint32_t m_duelCountdownTimer
Definition Player.hpp:1729
void setSkillInfoId(uint32_t index, uint8_t offset, uint16_t id)
Definition Player.cpp:1021
bool hasPendingBind() const
Definition Player.hpp:2138
void setResistanceBuffModPositive(uint8_t type, uint32_t value)
Definition Player.cpp:1195
void clearGlobalCooldown()
Definition Player.cpp:4449
void addVisibleObject(uint64_t guid)
Definition Player.cpp:3587
void setPendingBattleground(Battleground *bg)
Definition Player.cpp:8550
void setLootGuid(const uint64_t &guid)
Definition Player.cpp:10788
void handleDuelCountdown()
Definition Player.cpp:12099
uint32_t m_flatResistanceModifierPos[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2051
uint32_t m_FirstTalentTreeLock
Definition Player.hpp:1990
QuestLogEntry * getQuestLogByQuestId(uint32_t questId) const
Definition Player.cpp:8859
void setVanityPetSlotItemGuid(uint8_t slot, uint64_t guid)
Definition Player.cpp:967
static UpdateMask m_visibleUpdateMask
Definition Player.hpp:772
bool isTeamAlliance() const
Definition Player.cpp:2788
utf8_string m_name
Definition Player.hpp:735
void updateKnownCurrencies(uint32_t itemId, bool apply)
Definition Player.cpp:13232
uint32_t getPlayerFlags() const
Definition Player.cpp:768
std::map< uint32_t, uint32_t > m_wratings
Definition Player.hpp:1932
const WoWPlayer * playerData() const
Definition Player.hpp:126
uint32_t getMountSpellId() const
Definition Player.cpp:1512
void setInvitedByGuildId(uint32_t GuildId)
Definition Player.cpp:7863
bool isQueuedForBg() const
Definition Player.cpp:8552
void setWatchedFaction(uint32_t factionId)
Definition Player.cpp:1139
uint32_t m_baseResistanceModPctPos[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2053
void setResurrectHealth(uint32_t health)
Definition Player.cpp:7775
void calcResistance(uint8_t type)
Definition Player.cpp:15839
void buildRepop()
Definition Player.cpp:7711
LocationVector getCorpseLocation() const
Definition Player.cpp:7425
PlayerTeam getBgTeam() const
Definition Player.cpp:2775
void sendDelayedPacket(WorldPacket *data, bool deleteDataOnSend)
Definition Player.cpp:3230
void setTalentPoints(uint32_t talentPoints, bool forBothSpecs=true)
Definition Player.cpp:6017
void _addCategoryCooldown(uint32_t categoryId, uint32_t time, uint32_t SpellId, uint32_t ItemId)
Definition Player.cpp:4575
void setActionButton(uint8_t button, uint32_t action, uint8_t type, uint8_t misc)
Definition Player.cpp:6374
void setRangedCritPercentage(float value)
Definition Player.cpp:1104
void setMapEntryPoint(uint32_t mapId)
Definition Player.cpp:2050
std::unique_ptr< TradeData > m_TradeData
Definition Player.hpp:1050
void addQuestToRemove(uint32_t questId)
Definition Player.cpp:8925
void summonTemporarilyUnsummonedPet()
Definition Player.cpp:12556
void handleBreathing(MovementInfo const &movement_info, WorldSession *session)
Definition Player.cpp:1554
bool isInFlight() const
Definition Player.cpp:10770
std::map< uint8_t, uint8_t > const & getPetCachedSlotMap() const
Definition Player.cpp:12299
void modifySkillBonus(uint16_t skillLine, int16_t amount, bool permanentBonus)
Definition Player.cpp:5004
uint32_t m_totalStatModPctPos[5]
Definition Player.hpp:2074
void modFactionStanding(uint32_t faction, int32_t value)
Definition Player.cpp:11448
bool isSummoningDisabled() const
Definition Player.cpp:2326
void setFactionInactive(uint32_t faction, bool set)
Definition Player.cpp:11702
virtual bool isClassDruid() const
Definition Player.cpp:2772
uint32_t getSelfResurrectSpell() const
Definition Player.cpp:1135
void setTemporarilyUnsummonedPetsOffline()
Definition Player.cpp:12633
std::unique_ptr< TaxiPath > m_taxi
Definition Player.hpp:1629
Guild * getGuild() const
Definition Player.cpp:7865
void advanceAllSkills(uint16_t amount=1)
Definition Player.cpp:4705
uint32_t m_playedTime[3]
Definition Player.hpp:743
uint64_t m_lootGuid
Definition Player.hpp:1648
void incrementHonorless()
Definition Player.cpp:8193
bool m_changingMaps
Definition Player.hpp:2179
uint32_t getGuildRankFromDB()
Definition Player.cpp:7868
void addToFriendList(std::string name, std::string note)
Definition Player.cpp:9120
void setMaxLevel(uint32_t level)
Definition Player.cpp:1158
void addNoteToFriend(uint32_t guid, std::string note)
Definition Player.cpp:9197
void modCombatRating(uint8_t combatRating, int32_t value)
Definition Player.cpp:1278
void setSelfResurrectSpell(uint32_t spell)
Definition Player.cpp:1136
void completeLoading()
Definition Player.cpp:16200
void sendMovie(uint32_t movieId)
Definition Player.cpp:9386
uint32_t getHonor() const
Definition Player.cpp:8147
void sendExploreExperiencePacket(uint32_t areaId, uint32_t experience)
Definition Player.cpp:9671
bool isQueuedForRbg() const
Definition Player.cpp:8559
void sendPartyKillLogPacket(uint64_t killedGuid)
Definition Player.cpp:9606
void setIsQueuedForBg(bool set)
Definition Player.cpp:8553
void setBgQueueType(uint32_t type)
Definition Player.cpp:8574
uint32_t m_drunkTimer
Definition Player.hpp:1705
bool isAllowedToCreateCorpse() const
Definition Player.cpp:7440
int32_t getFactionStanding(uint32_t faction)
Definition Player.cpp:11432
Unit * getUnitOwnerOrSelf() override
Definition Player.cpp:2806
bool m_isReadyToBeRemoved
Definition Player.hpp:123
void indoorCheckUpdate(uint32_t time)
Definition Player.cpp:2023
SpellSet m_spellSet
Definition Player.hpp:968
uint8_t m_cannibalizeCount
Definition Player.hpp:2096
void sendLogXpGainPacket(uint64_t guid, uint32_t normalXp, uint32_t restedXp, bool type)
Definition Player.cpp:12198
void updateHonor()
Definition Player.cpp:8162
uint32_t getBuybackTimestampSlot(uint8_t slot) const
Definition Player.cpp:1245
void spawnPet(uint8_t petId)
Definition Player.cpp:12538
virtual bool isClassPaladin() const
Definition Player.cpp:2770
bool teleport(const LocationVector &vec, WorldMap *map)
Definition Player.cpp:1742
Item * storeNewLootItem(uint8_t slot, Loot *loot)
Definition Player.cpp:11163
bool m_isGmInvisible
Definition Player.hpp:1096
void addToGMTargetList(uint32_t guid)
Definition Player.cpp:2399
uint32_t getGuildId() const
Definition Player.cpp:788
uint32_t m_statModPctNeg[5]
Definition Player.hpp:2073
uint32_t m_manaFromSpell
Definition Player.hpp:2218
uint32_t m_honorPoints
Definition Player.hpp:1383
SpellSet const & getDeletedSpellSet() const
Definition Player.cpp:3965
uint32_t getFreeTalentPoints() const
Definition Player.cpp:1030
std::set< uint32_t > m_removequests
Definition Player.hpp:1526
void removeShapeShiftSpell(uint32_t spellId)
Definition Player.cpp:4074
float m_noseLevel
Definition Player.hpp:627
void Update(unsigned long time_passed)
Definition Player.cpp:290
void setResurrecterGuid(uint64_t guid)
Definition Player.cpp:7774
uint32_t m_talentResetsCount
Definition Player.hpp:1012
PlayerSpec & getActiveSpec()
Definition Player.cpp:9393
bool isIgnored(uint32_t guid) const
Definition Player.cpp:9358
void sendRaidInfo()
Definition Player.cpp:12927
void setPlayerFieldBytes2(uint32_t bytes)
void setParryPercentage(float value)
Definition Player.cpp:1088
uint32_t m_pendingBindTimer
Definition Player.hpp:2157
bool m_enteringWorld
Definition Player.hpp:785
void tagUnit(Object *object)
Definition Player.cpp:10156
uint16_t getSkillLineMax(uint16_t skillLine) const
Definition Player.cpp:4944
void _loadPlayerCooldowns(QueryResult *result)
Definition Player.cpp:4627
BoundInstancesMap m_boundInstances[InstanceDifficulty::MAX_DIFFICULTY]
Definition Player.hpp:2126
bool isInFeralForm()
Definition Player.cpp:4113
uint64_t m_comboTarget
Definition Player.hpp:984
uint8_t getDungeonDifficulty()
Definition Player.cpp:7241
uint32_t m_banned
Definition Player.hpp:1106
void togglePvP()
Definition Player.cpp:8343
bool isBanned() const
Definition Player.cpp:2330
void saveToDB(bool newCharacter)
Definition Player.cpp:14132
void setCombatRating(uint8_t combatRating, uint32_t value)
Definition Player.cpp:1277
void removeSkillSpells(uint16_t skillLine)
Definition Player.cpp:5145
void sendTimeSync()
Definition Player.cpp:10322
void sendPlaySoundPacket(uint32_t soundId)
Definition Player.cpp:9666
Battleground * m_pendingBattleground
Definition Player.hpp:1456
void fillRandomBattlegroundReward(bool wonBattleground, uint32_t &honorPoints, uint32_t &arenaPoints)
Definition Player.cpp:8583
void sendSpellModifierPacket(uint8_t spellType, std::vector< std::pair< uint8_t, float > > modValues, bool isPct)
Definition Player.cpp:9690
uint32_t m_timeSyncClient
Definition Player.hpp:1924
void setEnabledActionBars(uint8_t actionBarId)
Definition Player.cpp:1235
void regeneratePlayerPowers(uint16_t diff)
Definition Player.cpp:3781
void setPlayerBytes3(uint32_t bytes3)
Definition Player.cpp:853
void sendInstanceResetWarning(uint32_t mapid, InstanceDifficulty::Difficulties difficulty, uint32_t time, bool welcome)
Definition Player.cpp:13016
bool hasEnoughCoinage(uint64_t coinage) const
Definition Player.cpp:1186
QuestLogEntry * createQuestLogInSlot(QuestProperties const *questProperties, uint8_t slotId)
Definition Player.cpp:8818
void eventAttackStart()
Definition Player.cpp:13770
void setKnownPvPTitle(RankTitles title, bool set)
Definition Player.cpp:8526
bool hasPetInSlot(uint8_t slot) const
Definition Player.cpp:12344
uint32_t getExpertise() const
Definition Player.cpp:1091
bool hasQueuedBgInstanceId() const
Definition Player.cpp:8555
static PlayerBytes3_DrunkValue getDrunkStateByValue(uint16_t value)
Definition Player.cpp:11851
void resetAllTalents()
Definition Player.cpp:5996
bool logOntoTransport()
Definition Player.cpp:9424
ArenaTeam * getArenaTeam(uint8_t type)
Definition Player.cpp:8070
void bindToInstance()
Definition Player.cpp:12903
void updateArenaPoints()
Definition Player.cpp:8117
uint32_t m_resistanceModPctPos[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2055
uint32_t m_lastPotionId
Definition Player.hpp:916
void setManaRegeneration(float value)
Definition Player.cpp:1143
void setGuildRank(uint32_t guildRank)
Definition Player.cpp:813
bool hasQuestInQuestLog(uint32_t questId) const
Definition Player.cpp:8842
void removePendingPlayer()
Definition Player.cpp:3134
uint32_t getBgQueueType() const
Definition Player.cpp:8575
void OnPushToWorld() override
Definition Player.cpp:555
void removeFromBgQueue()
Definition Player.cpp:8562
void setLoginFlag(uint32_t flag)
Definition Player.cpp:2643
void modFreePrimaryProfessionPoints(int32_t amount)
Definition Player.cpp:1064
bool isPvpFlagSet() const override
Definition Player.cpp:9781
void _eventAttack(bool offhand)
Definition Player.cpp:13615
Standing getFactionStandingRank(uint32_t faction)
Definition Player.cpp:11519
void AddToWorld()
Definition Player.cpp:473
uint32_t getKillsToday() const
Definition Player.cpp:8209
bool isPetRequiringTemporaryUnsummon() const
Definition Player.cpp:12593
void resetTimeSync()
Definition Player.cpp:10314
uint32_t getArenaPoints() const
Definition Player.cpp:8102
void updateAutoRepeatSpell()
Definition Player.cpp:4166
bool isInGuild()
Definition Player.cpp:7866
void eventKickFromServer()
Definition Player.cpp:2368
void resurrect()
Definition Player.cpp:7671
bool m_hasWonRbgToday
Definition Player.hpp:1462
uint32_t buildCreateUpdateBlockForPlayer(ByteBuffer *data, Player *target) override
This includes any nested objects we have, inventory for example.
Definition Player.cpp:3303
Player * getPlayerOwner() override
Definition Player.cpp:2822
uint32_t getLastBattlegroundPetSpell() const
Definition Player.cpp:12660
void sendUpdateToOutOfRangeGroupMembers()
Definition Player.cpp:7933
void setVisibleItemEntry(uint32_t slot, uint32_t entry)
Definition Player.cpp:922
void updateComboPoints()
Definition Player.cpp:5387
uint8_t getSkinColor() const
Definition Player.cpp:824
uint32_t m_totalStatModPctNeg[5]
Definition Player.hpp:2075
Object * m_summonedObject
Definition Player.hpp:1811
bool hasQuestForItem(uint32_t itemId) const
Definition Player.cpp:8951
void setGroupInviterId(uint32_t inviterId)
Definition Player.cpp:7881
void sendCinematicCamera(uint32_t id)
Definition Player.cpp:10276
void setSummonedObject(Object *summonedObject)
Definition Player.cpp:12705
void sendPetUnlearnConfirmPacket()
Definition Player.cpp:9560
void _saveQuestLogEntry(QueryBuffer *buf)
Definition Player.cpp:14481
uint32_t getPlayerBytes() const
Definition Player.cpp:821
uint32_t getDuelTeam() const
Definition Player.cpp:870
void setBanned(uint32_t timestamp=4, std::string Reason="")
Definition Player.cpp:2340
uint16_t m_holyPowerRegenerateTimer
Definition Player.hpp:829
void setQuestLogStateBySlot(uint8_t slot, uint32_t state)
Definition Player.cpp:890
bool hasOffHandWeapon() const
Definition Player.cpp:6629
void toggleXpGain()
Definition Player.cpp:12203
uint32_t getModHealingDone() const
Definition Player.cpp:1213
void sendTalentResetConfirmPacket()
Definition Player.cpp:9555
void OnPrePushToWorld() override
Definition Player.cpp:538
void sendDungeonDifficultyPacket()
Definition Player.cpp:9572
bool canGainXp() const
Definition Player.cpp:12204
void sendClientControlPacket(Unit *target, uint8_t allowMove)
Definition Player.cpp:9732
void activateTalentSpec(uint8_t specId)
Definition Player.cpp:6237
uint32_t m_grouIdpInviterId
Definition Player.hpp:1318
void setBankBagSlotItemGuid(uint8_t slot, uint64_t guid)
Definition Player.cpp:955
void eventCannibalize(uint32_t amount)
Definition Player.cpp:15814
uint32_t m_invitedByGuildId
Definition Player.hpp:1287
void cooldownAddItem(ItemProperties const *itemProp, uint32_t spellIndex)
Definition Player.cpp:4478
void removeVisibleObject(uint64_t guid)
Definition Player.cpp:3588
void setTalentResetsCount(uint32_t value)
Definition Player.cpp:6319
void updateManaRegeneration(bool initialUpdate=false)
void eventCharmAttack()
Definition Player.cpp:13699
bool m_resendSpeed
Definition Player.hpp:2180
void setQuestLogRequiredMobOrGoBySlot(uint8_t slot, uint32_t mobOrGoCount)
Definition Player.cpp:902
WorldSession * m_session
Definition Player.hpp:788
bool isAtGroupRewardDistance(Object *pRewardSource)
Definition Player.cpp:10137
void setShieldBlockCritPercentage(float value)
Definition Player.cpp:1119
void removePlayerFlags(uint32_t flags)
Definition Player.cpp:785
void _loadPetSpells(QueryResult *result)
Definition Player.cpp:14118
void buildFlagUpdateForNonGroupSet(uint32_t index, uint32_t flag)
Definition Player.cpp:16185
uint32_t m_indoorCheckTimer
Definition Player.hpp:633
uint32_t getTutorialValueById(uint8_t id)
Definition Player.cpp:6334
uint32_t m_modBlockValueFromSpells
Definition Player.hpp:2049
int32_t getBGEntryInstanceId() const
Definition Player.cpp:7831
Player(uint32_t guid)
Definition Player.cpp:202
uint64_t getKnownCurrencies() const
Definition Player.cpp:989
uint32_t m_modBlockAbsorbValue
Definition Player.hpp:2048
void cancelDuel()
Definition Player.cpp:12074
uint16_t m_serversideDrunkValue
Definition Player.hpp:1706
uint32_t m_globalCooldown
Definition Player.hpp:918
void setModTargetPhysicalResistance(uint32_t value)
Definition Player.cpp:1222
float getParryChance()
Definition Player.cpp:15392
void setModTargetResistance(uint32_t value)
Definition Player.cpp:1218
void outPacketToSet(uint16_t opcode, uint16_t length, const void *data, bool sendToSelf) override
Definition Player.cpp:3167
bool isGroupLeader() const
Definition Player.cpp:7888
PlayerSpec m_spec
Definition Player.hpp:1996
uint32_t m_loadMana
Definition Player.hpp:731
uint32_t getQuestLogRequiredMobOrGoForSlot(uint8_t slot) const
Definition Player.cpp:901
uint64_t getCurrencyTokenSlotItemGuid(uint8_t slot) const
Definition Player.cpp:971
void setPhase(uint8_t command=PHASE_SET, uint32_t newPhase=1) override
Definition Player.cpp:2063
std::vector< uint32_t > m_socialIgnoring
Definition Player.hpp:1565
uint32_t getMaxLevel() const
Definition Player.cpp:1149
LocationVector m_resurrectPosition
Definition Player.hpp:1221
void setPlayerFieldBytesMiscFlag(uint8_t miscFlag)
Definition Player.cpp:1230
void removeGarbageItems()
Definition Player.cpp:6970
void applyRandomBattlegroundReward(bool wonBattleground)
Definition Player.cpp:8607
uint8_t m_stableSlotCount
Definition Player.hpp:1808
uint32_t getGlyphSlot(uint16_t slot) const
Definition Player.cpp:1306
void setBuybackTimestampSlot(uint8_t slot, uint32_t timestamp)
Definition Player.cpp:1246
void setResistanceBuffModNegative(uint8_t type, uint32_t value)
Definition Player.cpp:1198
bool m_attacking
Definition Player.hpp:2209
bool m_requiresNoAmmo
Definition Player.hpp:2043
void decrementHonorless()
Definition Player.cpp:8194
bool m_isTurning
Definition Player.hpp:621
float calcRating(PlayerCombatRating t)
Definition Player.cpp:16170
uint32_t m_resurrectMana
Definition Player.hpp:1218
void joinedChannel(Channel *channel)
Definition Player.cpp:7960
std::unique_ptr< SpeedCheatDetector > m_speedCheatDetector
Definition Player.hpp:1575
uint32_t getMainMeleeDamage(uint32_t attackPowerOverride)
Definition Player.cpp:16836
bool isInGroup() const
Definition Player.cpp:7885
ReputationMap m_reputation
Definition Player.hpp:1690
void broadcastMessage(const char *Format,...)
Definition Player.cpp:6552
void sendGossipPoiPacket(float posX, float posY, uint32_t icon, uint32_t flags, uint32_t data, std::string name)
Definition Player.cpp:9635
void addXP(uint32_t xp)
Definition Player.cpp:995
std::vector< uint32_t > m_socialFriendedByGuids
Definition Player.hpp:1562
uint32_t m_baseResistanceModPctNeg[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2054
void sendInstanceDifficultyPacket(uint8_t difficulty)
Definition Player.cpp:9591
uint32_t m_honorless
Definition Player.hpp:1390
uint8_t getAuraVision() const
void updateRunicPowerRegeneration(bool initialUpdate=false)
void setCorpseData(LocationVector position, int32_t instanceId)
Definition Player.cpp:7419
std::string getAFKReason() const
Definition Player.cpp:2397
uint32_t armorProficiency
Definition Player.hpp:981
bool hasQuestMob(uint32_t entry)
Definition Player.cpp:9000
uint32_t getResistanceBuffModPositive(uint8_t type) const
Definition Player.cpp:1194
bool isGMFlagSet() const
Definition Player.cpp:9381
void displayTimerList()
Definition Player.cpp:13276
void _Relocate(uint32_t mapid, const LocationVector &v, bool sendpending, bool force_new_world, uint32_t instance_id)
Definition Player.cpp:15954
uint8_t m_dungeonDifficulty
Definition Player.hpp:1168
void setRestStateXp(uint32_t xp)
Definition Player.cpp:1173
std::unique_ptr< Mailbox > m_mailBox
Definition Player.hpp:2188
void onModStanding(WDB::Structures::FactionEntry const *factionEntry, FactionReputation *reputation)
Definition Player.cpp:11733
uint8_t m_duelState
Definition Player.hpp:1728
void resetFinishedDailies()
Definition Player.cpp:8892
void setSession(WorldSession *session)
Definition Player.cpp:3132
uint8_t getDrunkValue() const
Definition Player.cpp:858
PlayerCooldownMap m_cooldownMap[NUM_COOLDOWN_TYPES]
Definition Player.hpp:917
void sendForceMovePacket(UnitSpeedType speed_type, float speed)
Definition Player.cpp:1321
const uint64_t & getLootGuid() const
Definition Player.cpp:10787
WorldSession * getSession() const
Definition Player.cpp:3131
SpellSet const & getSpellSet() const
Definition Player.cpp:3960
void _castSpellArea()
Definition Player.cpp:13528
uint32_t m_resurrectInstanceID
Definition Player.hpp:1219
bool removeDeletedSpell(uint32_t spellId)
Definition Player.cpp:3950
uint32_t getHonorYesterday() const
Definition Player.cpp:8191
void loadFromDBProc(QueryResultVector &results)
Definition Player.cpp:14560
std::mutex m_mutexIgnoreList
Definition Player.hpp:1566
void removeFromFriendList(uint32_t guid)
Definition Player.cpp:9177
void _savePet(QueryBuffer *buf, bool updateCurrentPetCache=false, Pet *currentPet=nullptr)
Definition Player.cpp:13794
Battleground * getBattleground() const
Definition Player.cpp:8546
void _spawnPet(PetCache const *petCache)
Definition Player.cpp:12707
uint32_t getBGEntryMapId() const
Definition Player.cpp:7830
void setNextLevelXp(uint32_t xp)
Definition Player.cpp:998
void displayCreatureSetForEntry(uint32_t _creatureEntry)
Definition Player.cpp:13282
void giveXp(uint32_t xp, const uint64_t &guid, bool allowBonus)
Definition Player.cpp:12133
int32_t getPctReputationMod() const
Definition Player.cpp:11820
bool saveSkills(bool newCharacter, QueryBuffer *buf)
Definition Player.cpp:13484
uint16_t getServersideDrunkValue() const
Definition Player.cpp:11827
void setDuelArbiter(uint64_t guid)
Definition Player.cpp:766
void saveTutorials()
Definition Player.cpp:6361
void sendMountResultPacket(uint32_t result)
Definition Player.cpp:9704
void sendEquipmentSetUseResultPacket(uint8_t result)
Definition Player.cpp:9616
void loadTutorials()
Definition Player.cpp:6350
void addWeaponProficiency(uint32_t proficiency)
Definition Player.cpp:5243
bool saveSpells(bool newCharacter, QueryBuffer *buf)
Definition Player.cpp:13393
uint32_t m_arenaPoints
Definition Player.hpp:1358
uint32_t getModDamageDoneNegative(uint16_t school) const
Definition Player.cpp:1205
void unbindInstance(uint32_t mapid, InstanceDifficulty::Difficulties difficulty, bool unload=false)
Definition Player.cpp:12831
void spawnCorpseBones()
Definition Player.cpp:7531
void setBindPoint(float x, float y, float z, float o, uint32_t mapId, uint32_t zoneId)
Definition Player.cpp:7809
void setFacialFeatures(uint8_t feature)
Definition Player.cpp:842
uint8_t m_maxPetNumber
Definition Player.hpp:1809
void eventTeleport(uint32_t mapId, LocationVector position, uint32_t instanceId=0)
Definition Player.cpp:1767
void setupPvPOnLogin()
Definition Player.cpp:8218
LocationVector m_sentTeleportPosition
Definition Player.hpp:629
void resetSpells()
Definition Player.cpp:4039
void sendCinematicOnFirstLogin()
Definition Player.cpp:9536
void _savePetSpells(QueryBuffer *buf)
Definition Player.cpp:13948
void loadFriendedByOthersList()
Definition Player.cpp:9090
bool m_bgHasFlag
Definition Player.hpp:1466
void setGlyphsEnabled(uint32_t glyphs)
Definition Player.cpp:1313
void addToInRangeObjects(Object *object) override
Definition Player.cpp:15775
uint32_t getBindZoneId() const
Definition Player.cpp:7818
bool _removeSpell(uint32_t spellId, bool moveToDeleted, bool silently=false, bool removingPreviousRank=false, bool forceRemoveHigherRanks=false)
Definition Player.cpp:5594
uint32_t getKillsYesterday() const
Definition Player.cpp:8211
void setLastBattlegroundPetSpell(uint32_t petSpell)
Definition Player.cpp:12659
void clearInRangeSets() override
Definition Player.cpp:15808
void setMountVehicleId(uint32_t id)
Definition Player.cpp:1517
uint32_t m_battlegroundLastPetSpell
Definition Player.hpp:1806
uint64_t getVanityPetSlotItemGuid(uint8_t slot) const
Definition Player.cpp:966
float getShieldBlockCritPercentage() const
Definition Player.cpp:1118
void sendTeleportPacket(LocationVector position)
Definition Player.cpp:1895
uint8_t m_restState
Definition Player.hpp:1750
bool create(CharCreate &charCreateContent)
Definition Player.cpp:2422
bool isSpellFitByClassAndRace(uint32_t spell_id) const
Definition Player.cpp:4271
uint64_t getInventorySlotItemGuid(uint8_t slot) const
Definition Player.cpp:945
uint32_t m_killsLifetime
Definition Player.hpp:1393
void removeSkillLine(uint16_t skillLine)
Definition Player.cpp:5068
int32_t m_pctReputationMod
Definition Player.hpp:1691
void sendActionBars(uint8_t action)
Definition Player.cpp:6384
uint32_t getQuestLogExpireTimeForSlot(uint8_t slot) const
Definition Player.cpp:916
uint32_t m_explorationTimer
Definition Player.hpp:649
uint32_t m_loginFlag
Definition Player.hpp:737
float m_spellHasteRatingBonus
Definition Player.hpp:2021
void updateNearbyQuestGameObjects()
Definition Player.cpp:9043
void calcStat(uint8_t t)
Definition Player.cpp:15895
void sendSummonRequest(uint32_t requesterId, uint32_t zoneId, uint32_t mapId, uint32_t instanceId, const LocationVector &position)
Definition Player.cpp:2386
void removeIfVisiblePushOutOfRange(uint64_t guid)
Definition Player.cpp:3601
uint32_t getInitialTeam() const
Definition Player.cpp:2779
Battleground * getPendingBattleground() const
Definition Player.cpp:8549
Field * Fetch()
Definition Database.h:195
virtual bool NextRow()=0
uint32_t GetFieldCount() const
Definition Database.h:196
uint32_t getCategoryRecoveryTime() const
bool hasSpellRanks() const
uint32_t getStartRecoveryTime() const
uint32_t getEffectApplyAuraName(uint8_t idx) const
uint32_t getDmgClass() const
uint32_t getAttributes() const
uint32_t getId() const
uint32_t getStartRecoveryCategory() const
uint32_t getRequiredShapeShift() const
int32_t getEffectBasePoints(uint8_t idx) const
int32_t getEquippedItemClass() const
uint32_t getRecoveryTime() const
SpellRankInfo const * getRankInfo() const
uint32_t getEffect(uint8_t idx) const
int32_t getEquippedItemSubClass() const
uint32_t getCategory() const
uint32_t castedItemId
Definition Spell.hpp:684
Unit * getUnitTarget() const
Definition Spell.cpp:5682
SpellCastResult prepare(SpellCastTargets *targets)
Definition Spell.cpp:255
void setPvPFlags(bool set)
void setSanctuaryFlags(bool set)
void setPhase(uint8_t command, uint32_t newPhase)
std::vector< Summon * > const & getSummons() const
void setFFAPvPFlags(bool set)
bool isPermanentSummon() const
Definition Summon.cpp:260
Definition Unit.hpp:147
bool isInCombat() const
Definition Unit.hpp:289
void setMaxRangedDamage(float damage)
Definition Unit.cpp:1600
void setStat(uint8_t stat, uint32_t value)
Definition Unit.cpp:1449
bool hasUnitStateFlag(uint32_t state_flag) const
Definition Unit.hpp:717
bool hasAurasWithId(uint32_t auraId) const
Definition Unit.cpp:5004
void setCombatReach(float radius)
Definition Unit.cpp:1250
GameObject * getGameObject(uint32_t spellId) const
Definition Unit.cpp:8702
void eventModelChange()
Definition Unit.cpp:9091
SpellCastResult castSpell(uint64_t targetGuid, uint32_t spellId, bool triggered=false)
Definition Unit.cpp:3564
Player * m_playerControler
Definition Unit.hpp:695
float getAttackPowerMultiplier() const
Definition Unit.cpp:1654
void setMaxOffhandDamage(float damage)
Definition Unit.cpp:1291
uint64_t getNpcFlags() const
Definition Unit.cpp:1439
void removeProcTriggerSpell(uint32_t spellId, uint64_t casterGuid=0, uint64_t misc=0)
Definition Unit.cpp:3773
void setMoveWaterWalk()
Definition Unit.cpp:1992
void setEmoteState(uint32_t id)
Definition Unit.cpp:1446
void interruptHealthRegeneration(uint32_t timeInMS)
Definition Unit.cpp:6653
uint32_t getMaxPower(PowerType type) const
Definition Unit.cpp:654
void addUnitFlags(uint32_t unitFlags)
Definition Unit.cpp:1109
void setClass(uint8_t class_)
Definition Unit.cpp:457
float m_baseRangedDamage[2]
Definition Unit.hpp:1398
float getAttackSpeedModifier(WeaponDamageType type) const
Definition Unit.cpp:6930
int32_t m_healDoneMod[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1445
uint32_t isStunned() const
Definition Unit.hpp:1351
void setHealthPct(uint32_t val)
Definition Unit.cpp:514
void setMinOffhandDamage(float damage)
Definition Unit.cpp:1288
bool m_isDisarmed
Definition Unit.hpp:1479
bool hasAuraState(AuraState state, SpellInfo const *spellInfo=nullptr, Unit const *caster=nullptr) const
Definition Unit.cpp:5130
PowerType getPowerType() const
Definition Unit.cpp:462
void removeUnitFlags(uint32_t unitFlags)
Definition Unit.cpp:1110
void Update(unsigned long time_passed)
Definition Unit.cpp:157
void setPositiveAuraLimit(uint8_t limit)
Definition Unit.cpp:1553
bool hasUnitFlags(uint32_t unitFlags) const
Definition Unit.cpp:1111
void setMountDisplayId(uint32_t id)
Definition Unit.cpp:1279
float getCombatReach() const
Definition Unit.cpp:1249
uint32_t getStat(uint8_t stat) const
Definition Unit.cpp:1448
float getSpeedRate(UnitSpeedType type, bool current) const
Definition Unit.cpp:2549
uint64_t getTargetGuid() const
Definition Unit.cpp:400
bool canDualWield() const
Definition Unit.cpp:3537
uint8_t getClass() const
Definition Unit.cpp:456
void applySpellModifiers(SpellModifierType modType, T *value, SpellInfo const *spellInfo, Spell *castingSpell=nullptr, Aura *castingAura=nullptr)
Definition Unit.cpp:4465
void sendEnvironmentalDamageLogPacket(uint64_t guid, uint8_t type, uint32_t damage, uint64_t unk=0)
Definition Unit.cpp:6935
uint64_t getCharmGuid() const
Definition Unit.cpp:380
void setOnMeleeSpell(uint32_t spellId, uint8_t ecn=0)
Definition Unit.hpp:1333
bool isAttackReady(WeaponDamageType type) const
Definition Unit.cpp:6912
void setPowerCostModifier(uint16_t school, uint32_t modifier)
Definition Unit.cpp:1603
void setMaxHealth(uint32_t maxHealth)
Definition Unit.cpp:626
void modHealth(int32_t health)
Definition Unit.cpp:502
uint32_t getDisplayId() const
Definition Unit.cpp:1252
uint32_t getOnMeleeSpell() const
Definition Unit.hpp:1334
float m_baseOffhandDamage[2]
Definition Unit.hpp:1394
virtual void OnPushToWorld()
Definition Unit.cpp:353
virtual void onRemoveInRangeObject(Object *pObj)
Definition Unit.cpp:7573
void setGender(uint8_t gender)
Definition Unit.cpp:460
float m_baseDamage[2]
Definition Unit.hpp:1390
DeathState m_deathState
Definition Unit.hpp:1117
SpellProc * addProcTriggerSpell(uint32_t spellId, uint32_t originalSpellId, uint64_t casterGuid, uint32_t procChance, SpellProcFlags procFlags, SpellExtraProcFlags exProcFlags, uint32_t const *spellFamilyMask, uint32_t const *procClassMask=nullptr, Aura *createdByAura=nullptr, Object *obj=nullptr)
Definition Unit.cpp:3713
void addGameObject(GameObject *gameObj)
Definition Unit.cpp:8711
uint8_t getGender() const
Definition Unit.cpp:459
uint32_t getUnitFlags() const
Definition Unit.cpp:1107
void setCharmGuid(uint64_t guid)
Definition Unit.cpp:381
void sendPowerUpdate(bool self)
Definition Unit.cpp:6734
void setMinRangedDamage(float damage)
Definition Unit.cpp:1597
void setBaseHealth(uint32_t baseHealth)
Definition Unit.cpp:1474
void modRangedAttackPowerMods(int32_t modifier)
Definition Unit.cpp:1682
void updateFocusRegeneration(bool initialUpdate=false)
Definition UnitStats.cpp:45
void setMinDamage(float damage)
Definition Unit.cpp:1282
void setResistance(uint8_t type, uint32_t value)
Definition Unit.cpp:1460
uint64_t getCharmedByGuid() const
Definition Unit.cpp:391
uint8_t getShapeShiftForm() const
Definition Unit.cpp:1386
uint32_t getBaseHealth() const
Definition Unit.cpp:1473
void setDisplayId(uint32_t id)
Definition Unit.cpp:1253
void setPowerCostMultiplier(uint16_t school, float multiplier)
Definition Unit.cpp:1616
void setMoveLandWalk()
Definition Unit.cpp:2020
void smsg_AttackStop(Unit *pVictim)
Definition Unit.cpp:7533
bool hasAuraWithAuraEffect(AuraEffect type) const
Definition Unit.cpp:5060
void removeAllAurasByIdForGuid(uint32_t auraId, uint64_t guid, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5274
uint32_t getBaseMana() const
Definition Unit.cpp:1470
uint32_t getBaseAttackTime(uint8_t slot) const
Definition Unit.cpp:1233
void setSpeedRate(UnitSpeedType mtype, float rate, bool current)
Definition Unit.cpp:2668
void setAttackTimer(WeaponDamageType type, uint32_t time)
Definition Unit.cpp:6902
void addSimpleEnvironmentalDamageBatchEvent(EnviromentalDamage type, uint32_t damage, uint32_t absorbedDamage=0)
Definition Unit.cpp:7381
void setPower(PowerType type, uint32_t value, bool sendPacket=true, bool skipObjectUpdate=false)
Definition Unit.cpp:547
uint32_t getChannelSpellId() const
Definition Unit.cpp:406
void setAttackPowerMods(int32_t modifier)
Definition Unit.cpp:1633
Pet * getPet() const
Definition Unit.cpp:7929
void buildMovementPacket(ByteBuffer *data)
Definition Unit.cpp:8801
void setFaction(uint32_t factionId)
Definition Unit.hpp:261
Aura * getAuraWithAuraSlot(uint16_t auraSlot) const
Definition Unit.cpp:4944
float getBlockFromSpell() const
Definition Unit.hpp:1518
void setAttackPowerMultiplier(float multiplier)
Definition Unit.cpp:1655
uint32_t getMaxHealth() const
Definition Unit.cpp:625
virtual void setPhase(uint8_t command=PHASE_SET, uint32_t newPhase=1)
Definition Unit.cpp:1715
void setRangedAttackPowerMods(int32_t modifier)
Definition Unit.cpp:1672
void castOnMeleeSpell()
Definition Unit.cpp:9383
float m_spellCritPercentage
Definition Unit.hpp:769
virtual void setDeathState(DeathState state)
Definition Unit.cpp:7875
void setHealth(uint32_t health)
Definition Unit.cpp:482
void setRangedAttackPowerMultiplier(float multiplier)
Definition Unit.cpp:1694
virtual bool isCritter()
Definition Unit.hpp:1075
uint32_t getAttackTimer(WeaponDamageType type) const
Definition Unit.cpp:6907
uint8_t getRace() const
Definition Unit.cpp:453
uint32_t m_schoolImmunityList[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1451
void removeAllAurasById(uint32_t auraId, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5248
void setHoverHeight(float height)
Definition Unit.cpp:1704
void removeAllAurasByAuraEffect(AuraEffect effect, uint32_t skipSpell=0, bool removeOnlyEffect=false, uint64_t casterGuid=0, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5306
virtual void addToInRangeObjects(Object *pObj)
Definition Unit.cpp:7559
void sendFullAuraUpdate()
Definition Unit.cpp:5655
uint32_t getFactionTemplate() const
Definition Unit.cpp:957
SummonHandler * getSummonInterface()
Definition Unit.cpp:7943
uint32_t getNativeDisplayId() const
Definition Unit.cpp:1275
int32_t getCalculatedAttackPower() const
Definition Unit.cpp:1813
void updateEnergyRegeneration(bool initialUpdate=false)
Definition UnitStats.cpp:20
DeathState getDeathState() const
Definition Unit.cpp:7924
void removeAllNegativeAuras()
Definition Unit.cpp:5433
float getDodgeFromSpell() const
Definition Unit.hpp:1520
bool isMounted() const
Definition Unit.cpp:8541
float m_spellCritChanceSchool[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1452
void unPossess()
Definition Unit.cpp:9007
AuraArray const & getAuraList() const
Definition Unit.cpp:5747
ThreatManager & getThreatManager()
Definition Unit.hpp:1190
float getRangedAttackPowerMultiplier() const
Definition Unit.cpp:1693
void modMaxPower(PowerType type, int32_t value)
Definition Unit.cpp:739
void playSpellVisual(uint32_t visual_id, uint32_t type)
Definition Unit.cpp:3442
void clearInRangeSets()
Definition Unit.cpp:7585
void sendChatMessage(uint8_t type, uint32_t language, std::string msg, Unit *receiver=nullptr, uint32_t sessionLanguage=0)
Definition Unit.cpp:6851
AIInterface * getAIInterface() const
Definition Unit.hpp:705
Loot loot
Definition Unit.hpp:1221
void setLevel(uint32_t level)
Definition Unit.cpp:937
void setBoundingRadius(float radius)
Definition Unit.cpp:1247
Unit * m_controledUnit
Definition Unit.hpp:694
void setMaxDamage(float damage)
Definition Unit.cpp:1285
uint32_t getClassMask() const
Definition Unit.hpp:221
int32_t getCalculatedRangedAttackPower() const
Definition Unit.cpp:1822
void setRangedAttackPower(int32_t power)
Definition Unit.cpp:1594
bool isStealthed() const
Definition Unit.cpp:6205
uint32_t getHealth() const
Definition Unit.cpp:481
uint32_t isFeared() const
Definition Unit.hpp:1354
uint64_t getChannelObjectGuid() const
Definition Unit.cpp:403
void addAura(std::unique_ptr< Aura > aur)
Definition Unit.cpp:4538
float m_zAxisPosition
Definition Unit.hpp:612
void clearHealthBatch()
Definition Unit.cpp:7488
void dismount(bool resummonPet=true)
Definition Unit.cpp:8602
uint32_t getPower(PowerType type) const
Definition Unit.cpp:516
void setMoveRoot(bool set_root)
Definition Unit.cpp:2245
void modMaxHealth(int32_t maxHealth)
Definition Unit.cpp:643
bool isAlive() const
Definition Unit.cpp:7871
void modInvisibilityDetection(InvisibilityFlag flag, const int32_t amount)
Definition Unit.cpp:6225
void setNativeDisplayId(uint32_t id)
Definition Unit.cpp:1276
void setMaxPower(PowerType type, uint32_t value)
Definition Unit.cpp:685
bool sendPeriodicAuraLog(const WoWGuid &casterGuid, const WoWGuid &targetGuid, SpellInfo const *spellInfo, uint32_t amount, uint32_t overKillOrOverHeal, uint32_t absorbed, uint32_t resisted, AuraEffect auraEffect, bool isCritical, uint32_t miscValue=0, float gainMultiplier=0.0f)
Definition Unit.cpp:5716
void removeAllAurasByAuraInterruptFlag(uint32_t auraInterruptFlag, uint32_t skipSpellId=0)
Definition Unit.cpp:5290
uint32_t getLevel() const
Definition Unit.cpp:936
void setRace(uint8_t race)
Definition Unit.cpp:454
DamageInfo strike(Unit *pVictim, WeaponDamageType weaponType, SpellInfo const *ability, int32_t add_damage, int32_t pct_dmg_mod, uint32_t exclusive_damage, bool disable_proc, bool skip_hit_check, bool force_crit=false, Spell *castingSpell=nullptr)
Definition Unit.cpp:10407
CombatHandler & getCombatHandler()
Definition Unit.cpp:1803
bool canReachWithAttack(Unit *unitTarget)
Definition Unit.cpp:1831
uint32_t m_baseStats[5]
Definition Unit.hpp:1443
void setBaseMana(uint32_t baseMana)
Definition Unit.cpp:1471
float getModCastSpeed() const
Definition Unit.cpp:1421
AuraEffectList const & getAuraEffectList(AuraEffect effect) const
Definition Unit.cpp:5752
void updateSpeed()
Definition Unit.cpp:2954
virtual void RemoveFromWorld(bool free_guid)
Remove object from world.
Definition Unit.cpp:288
void setPowerType(uint8_t powerType)
Definition Unit.cpp:463
void modAttackPowerMods(int32_t modifier)
Definition Unit.cpp:1643
uint32_t getRaceMask() const
Definition Unit.hpp:217
void updateVisibility()
Definition Unit.cpp:6244
MovementManager * getMovementManager()
Definition Unit.hpp:655
uint32_t m_baseResistance[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1442
int32_t getInvisibilityDetection(InvisibilityFlag flag) const
Definition Unit.cpp:6215
void setDualWield(bool enable)
Definition Unit.cpp:3542
void setBaseAttackTime(uint8_t slot, uint32_t time)
Definition Unit.cpp:1234
void clearProcCooldowns()
Definition Unit.cpp:3791
void regeneratePower(PowerType type, uint16_t timePassed)
Definition Unit.cpp:6447
void setModCastSpeed(float modifier)
Definition Unit.cpp:1422
void setMoveCanFly(bool set_fly)
Definition Unit.cpp:2175
bool isDead() const
Definition Unit.cpp:7872
void setAttackPower(uint32_t value)
Definition Unit.cpp:1591
float getParryFromSpell() const
Definition Unit.hpp:1519
uint32_t getShapeShiftMask() const
Definition Unit.hpp:483
void processPendingUpdates()
void pushOutOfRangeGuid(const WoWGuid &guid)
void queueDelayedPacket(std::unique_ptr< WorldPacket > packet)
void pushUpdateData(ByteBuffer *data, uint32_t updateCount)
void SetCount(uint32_t valuesCount)
Definition UpdateMask.h:71
void SetBit(const uint32_t index)
Definition UpdateMask.h:39
static uint32_t getGuidLowPartFromUInt64(uint64_t guid)
Definition WoWGuid.h:228
bool isItem() const
Definition WoWGuid.h:292
bool isGameObject() const
Definition WoWGuid.h:297
bool isUnit() const
Definition WoWGuid.h:299
bool isCorpse() const
Definition WoWGuid.h:291
bool isPlayer() const
Definition WoWGuid.h:290
uint32_t getGuidLowPart() const
Definition WoWGuid.h:222
uint64_t getRawGuid() const
Definition WoWGuid.h:261
void Init(uint64_t guid)
Definition WoWGuid.h:176
InstanceDifficulty::Difficulties getDifficulty() const
Definition WorldMap.hpp:216
uint32_t getInstanceId() const
Definition WorldMap.hpp:255
GameObject * getGameObject(uint32_t guid)
InstanceScript * getScript()
BaseMap * getBaseMap() const
Definition WorldMap.hpp:320
WorldStatesHandler & getWorldStatesHandler()
void changeObjectLocation(Object *obj)
Creature * getCreature(uint32_t guid)
Player * getPlayer(uint32_t guid)
Unit * getUnit(const uint64_t &guid)
void getZoneAndAreaId(uint32_t phaseMask, uint32_t &zoneid, uint32_t &areaid, LocationVector const &pos)
GameObject * createGameObject(uint32_t entry)
DynamicObject * getDynamicObject(uint32_t guid)
uint16_t GetOpcode() const
Definition WorldPacket.h:27
void SetOpcode(uint16_t opcode)
Definition WorldPacket.h:28
void Initialize(uint16_t opcode, size_t newres=200)
Definition WorldPacket.h:20
void OutPacket(uint16_t opcode)
Player * m_loggingInPlayer
uint32_t GetAccountId() const
void sendDoFlight(uint32_t mountDisplayId, uint32_t path, uint32_t pathNode=0)
void sendVoidStorageTransferResult(uint8_t result)
bool HasFlag(uint32_t flag)
void sendTradeResult(TradeStatus result, uint64_t guid=0)
void SetInstance(uint32_t Instance)
void fullLogin(Player *player)
void SystemMessage(const char *format,...)
void SetPlayer(Player *plr)
void LogoutPlayer(bool Save)
void SendPacket(WorldPacket *packet)
WoWGuid m_MoverWoWGuid
bool hasPermissions() const
void sendCalendarRaidLockout(InstanceSaved const *save, bool add)
std::string GetAccountName()
void systemMessage(const std::string &format, Args &&... args)
bool HasGMPermissions() const
uint32_t _accountFlags
uint32_t language
void BuildInitWorldStatesForZone(uint32_t _zone, uint32_t _area, WorldPacket &_data) const
FMT_CONSTEXPR auto bg(detail::color_type background) noexcept -> text_style
Definition color.h:320
color
Definition color.h:16
static uint32_t * buffer
static void save(LexState *ls, int c)
Definition llex.c:57
static void check(LexState *ls, int c)
Definition lparser.c:107
static void field(LexState *ls, ConsControl *cc)
Definition lparser.c:902
static int add(void *a, void *b, void *c)
Definition ltm_desc.c:207
static int neg(void *a, void *b)
Definition ltm_desc.c:68
static l_noret error(LoadState *S, const char *why)
Definition lundump.c:40
std::array< uint32_t, MAX_ACTION_SLOT > SmsgPetActionsArray
std::vector< uint32_t > SmsgPetSpellsVector
static constexpr uint32_t packPetActionButtonData(uint32_t spellId, uint8_t state)
std::vector< std::string > split(const std::string &source, const std::string &seperator)
Seperates string by seperator (one char) returns string vecotr.
Definition Strings.cpp:39
void capitalize(std::string &str)
Capitalize word (uppercase first char, lowercase rest)
Definition Strings.cpp:28
@ TOTAL_SLOT_START
Definition AuraSlots.hpp:51
@ POSITIVE_SLOT_START
Definition AuraSlots.hpp:21
@ REMOVABLE_SLOT_START
Definition AuraSlots.hpp:48
@ POSITIVE_SLOT_END
Definition AuraSlots.hpp:22
@ NEGATIVE_SLOT_START
Definition AuraSlots.hpp:24
@ REMOVABLE_SLOT_END
Definition AuraSlots.hpp:49
@ NEGATIVE_SLOT_END
Definition AuraSlots.hpp:25
void apply(T *val)
@ AchievementProgress
Definition Player.cpp:14521
@ ERR_TaxiPlayerShapeshifted
Definition TaxiMgr.hpp:64
@ ERR_UnspecificError
Definition TaxiMgr.hpp:56
@ ERR_TaxiPlayerAlreadyMounted
Definition TaxiMgr.hpp:63
uint32_t getMSTime()
Definition Util.cpp:143
int32_t float2int32(float value)
Definition Narrow.cpp:18
time_t getTimeNow()
Definition Util.cpp:135
long long GetTimeDifferenceToNow(const std::chrono::high_resolution_clock::time_point &start_time)
Returns the difference between start_time and now in milliseconds.
Definition Util.cpp:150
uint32_t getGameTime()
Returns generated time value for client packets.
Definition Util.cpp:282
std::chrono::high_resolution_clock::time_point TimeNow()
Returns the current point in time.
Definition Util.cpp:130
constexpr auto count() -> size_t
Definition core.h:1222
Definition g3dmath.h:935
char buf[N_BUF]
Definition spewG.c:36
SERVER_DECL tm g_localTime
Definition Log.cpp:18
SERVER_DECL time_t UNIXTIME
Definition Log.cpp:17
uint32_t Id
uint64_t highestBid
WoWGuid highestBidderGuid
uint64_t getAuctionOutBid() const
the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
utf8_string name
WDB::Structures::SpellItemEnchantmentEntry const * Enchantment
Definition Item.hpp:29
struct GameObjectProperties::@162::@167 chest
BindExtensionState extendState
InstanceSaved * save
ItemDamage Damage[MAX_ITEM_PROTO_DAMAGES]
std::map< uint32_t, int32_t > resistanceStatsMap
ItemSpell Spells[MAX_ITEM_PROTO_SPELLS]
std::map< uint32_t, int32_t > generalStatsMap
uint32_t ScalingStatsFlag
uint32_t ContainerSlots
uint32_t ScalingStatsEntry
uint32_t itemscount
int32_t CategoryCooldown
int32_t Cooldown
uint32_t Category
uint32_t Id
uint32_t Stat[5]
uint32_t Mana
uint32_t HP
uint32_t charges
bool is_blocked
Definition LootItem.hpp:76
bool is_ffa
Definition LootItem.hpp:78
uint32_t itemId
Definition LootItem.hpp:54
LooterSet const & getAllowedLooters() const
Definition LootItem.hpp:92
uint8_t count
Definition LootItem.hpp:58
bool isAllowedForPlayer(Player const *player) const
Definition LootItem.cpp:60
WDB::Structures::ItemRandomPropertiesEntry const * iRandomProperty
Definition LootItem.hpp:60
bool is_looted
Definition LootItem.hpp:74
WDB::Structures::ItemRandomSuffixEntry const * iRandomSuffix
Definition LootItem.hpp:62
ItemProperties const * itemproto
Definition LootItem.hpp:56
Definition Loot.hpp:35
bool fillLoot(uint32_t lootId, LootTemplateMap const &tempelateStore, Player *lootOwner, bool personal, uint8_t lootMode=InstanceDifficulty::DUNGEON_NORMAL)
Definition Loot.cpp:30
bool empty() const
Definition Loot.hpp:62
bool isLooted() const
Definition Loot.hpp:65
void clear()
Definition Loot.cpp:125
LootItem * lootItemInSlot(uint32_t lootslot, Player const *player, Personaltem **qitem=nullptr, Personaltem **ffaitem=nullptr)
Definition Loot.cpp:137
uint64_t roundRobinPlayer
Definition Loot.hpp:44
PersonaltemMap const & getPlayerFFAItems() const
Definition Loot.hpp:37
void addLooter(uint32_t GUID)
Definition Loot.hpp:68
PersonaltemMap const & getPlayerQuestItems() const
Definition Loot.hpp:36
uint8_t unlootedCount
Definition Loot.hpp:43
uint32_t gold
Definition Loot.hpp:42
std::vector< LootItem > items
Definition Loot.hpp:39
void itemRemoved(uint8_t slot)
Definition Loot.cpp:253
std::vector< LootItem > quest_items
Definition Loot.hpp:40
static const float _minY
static const float _maxY
static const float _minX
static const float _maxX
void writeMovementInfo(ByteBuffer &data, uint16_t opcode, float custom_speed=0.f, ExtraMovementStatusElement *extras=nullptr) const
Definition Object.cpp:5465
ObjectGuid transport_guid
void clearTransportData()
bool hasMovementFlag(MovementFlags _flags) const
LocationVector const * getPosition() const
void setTransportData(ObjectGuid _guid, float x, float y, float z, float o, uint32_t time, int8_t seat)
uint8_t index
Definition Loot.hpp:21
bool is_looted
Definition Loot.hpp:22
uint32_t entry
uint32_t spellid
std::list< CreateInfo_SkillStruct > skills
std::set< uint32_t > spell_cast_list
std::list< CreateInfo_ItemStruct > items
std::set< uint32_t > spell_list
std::list< CreateInfo_ActionBarStruct > actionbars
WDB::Structures::SkillLineEntry const * Skill
PlayerSkillFieldPosition FieldPosition
uint16_t CurrentValue
uint16_t MaximumValue
LocationVector location
Definition Player.hpp:1257
uint32_t zoneId
Definition Player.hpp:1241
LocationVector location
Definition Player.hpp:1239
LocationVector location
Definition Player.hpp:1209
uint32_t instanceId
Definition Player.hpp:1114
LocationVector position
Definition Player.hpp:1115
uint32_t summonerId
Definition Player.hpp:1112
uint32_t required_itemcount[MAX_REQUIRED_QUEST_ITEM]
uint32_t receive_items[4]
uint32_t required_item[MAX_REQUIRED_QUEST_ITEM]
bool isSpellPartOfThisSpellRankChain(uint32_t spellId) const
Definition SpellInfo.cpp:50
uint32_t RequiredRepFaction
uint32_t RequiredRace
uint16_t RequiredSkill
uint32_t RequiredClass
uint32_t RequiredRepValue
uint32_t RequiredSkillLine
uint32_t itemSuffixFactor
uint32_t itemRandomPropertyId
uint32_t creatorGuid
char * map_name[NAME_PATTERN]
uint64_t data
Definition WoWObject.hpp:46
uint32_t player_flags
std::array< uint32_t, WOWPLAYER_SPELL_SCHOOL_COUNT > field_mod_damage_done_positive
uint32_t rest_state_xp
uint32_t track_creatures
uint32_t field_coinage
std::array< uint32_t, WOWPLAYER_EXPLORED_ZONES_COUNT > explored_zones
player_bytes_3_union player_bytes_3
std::array< uint64_t, WOWPLAYER_BANK_SLOT_COUNT > bank_slot
std::array< uint64_t, WOWPLAYER_BUY_BACK_COUNT > vendor_buy_back_slot
std::array< uint32_t, WOWPLAYER_COMBAT_RATING_COUNT > field_combat_rating
uint32_t track_resources
uint32_t self_resurrection_spell
uint32_t duel_team
std::array< uint64_t, WOWPLAYER_PACK_SLOT_COUNT > pack_slot
std::array< uint32_t, WOWPLAYER_BUY_BACK_COUNT > field_buy_back_price
player_bytes_2_union player_bytes_2
uint32_t character_points_1
uint32_t guild_rank
std::array< WoWPlayer_VisibleItem, WOWPLAYER_VISIBLE_ITEM_COUNT > visible_items
std::array< WoWPlayer_Quest, WOWPLAYER_QUEST_COUNT > quests
float ranged_crit_pct
std::array< uint64_t, WOWPLAYER_KEYRING_SLOT_COUNT > key_ring_slot
player_field_bytes_2_union player_field_bytes_2
uint64_t duel_arbiter
float parry_pct
std::array< uint32_t, WOWPLAYER_SPELL_SCHOOL_COUNT > field_mod_damage_done_negative
float dodge_pct
uint32_t guild_id
float crit_pct
std::array< uint32_t, WOWPLAYER_BUY_BACK_COUNT > field_buy_back_timestamp
player_bytes_union player_bytes
uint32_t next_level_xp
std::array< uint32_t, WOWPLAYER_SPELL_SCHOOL_COUNT > resistance_buff_mod_positive
player_field_bytes_union player_field_bytes
uint32_t field_lifetime_honorable_kills
std::array< float, WOWPLAYER_SPELL_SCHOOL_COUNT > field_mod_damage_done_pct
std::array< uint32_t, WOWPLAYER_SPELL_SCHOOL_COUNT > resistance_buff_mod_negative
float block_pct
uint32_t guild_timestamp
std::array< uint64_t, WOWPLAYER_BANK_BAG_SLOT_COUNT > bank_bag_slot
std::array< WoWPlayer_SkillInfo, WOWPLAYER_SKILL_INFO_COUNT > skill_info
std::array< uint64_t, WOWPLAYER_INVENTORY_SLOT_COUNT > inventory_slot
uint32_t character_points_2
uint32_t ammo_id
uint64_t farsight_guid
uint32_t field_watched_faction_idx
uint32_t xp
Definition adtfile.h:41
uInt avail_in
Definition zlib.h:87
Bytef * next_in
Definition zlib.h:86
alloc_func zalloc
Definition zlib.h:97
uInt avail_out
Definition zlib.h:91
Bytef * next_out
Definition zlib.h:90
free_func zfree
Definition zlib.h:98
voidpf opaque
Definition zlib.h:99
uLong total_out
Definition zlib.h:92
struct player_bytes_2_union::parts s
struct player_bytes_3_union::parts s
struct player_bytes_union::parts s
struct player_field_bytes_2_union::parts s
struct player_field_bytes_union::parts s
std::string utf8_string
signed short int16_t
unsigned short uint16_t
signed __int64 int64_t
unsigned int uint32_t
signed int int32_t
unsigned char uint8_t
unsigned __int64 uint64_t
signed char int8_t
@ HOUR
Definition Definitions.h:13